././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751582292.641044 aiosignal-1.4.0/0000755000175100001660000000000015031603125013061 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/.codecov.yml0000644000175100001660000000057415031603113015307 0ustar00runnerdockercoverage: 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/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/.coveragerc0000644000175100001660000000046615031603113015205 0ustar00runnerdocker[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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/CHANGES.rst0000644000175100001660000000567315031603113014673 0ustar00runnerdocker========= Changelog ========= .. You should *NOT* be adding new change log entries to this file, this file is managed by towncrier. You *may* edit previous change logs to fix problems like typo corrections or such. To add a new change log entry, please see https://pip.pypa.io/en/latest/development/contributing/#news-entries we named the news folder "changes". WARNING: Don't drop the next directive! .. 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 `_ - 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 `_, `#710 `_ Misc ---- - Removed the sphinxcontrib-asyncio documentation dependency. `#528 `_ ---- 1.3.2 (2024-12-13) ================== Deprecations and Removals ------------------------- - Dropped Python 3.7 support. `#413 `_ - Dropped Python 3.8 support. `#645 `_ Misc ---- - `#362 `_ ---- 1.3.1 (2022-11-08) ================== Bugfixes -------- - Removed stray quote and comma from setup.cfg preventing PyPI from accepting a release. `#361 `_ ---- 1.3.0 (2022-11-08) ================== Features -------- - Switched to declarative package setup. `#267 `_ - Added support for Python 3.11. `#360 `_ Deprecations and Removals ------------------------- - Dropped Python 3.6 support. `#267 `_ ---- 1.2.0 (2021-10-16) ================== Features -------- - Added support for Python 3.10. `#328 `_ Bugfixes -------- - Mark aiosignal as Python3-only package `#165 `_ ---- 1.1.2 (2020-11-27) ================== Features -------- - Fix MANIFEST.in to include ``aiosignal/py.typed`` marker 1.1.1 (2020-11-27) ================== Features -------- - Support type hints 1.1.0 (2020-10-13) ================== Features -------- - Added support of Python 3.8 and 3.9 1.0.0 (2019-11-11) ================== Deprecations and Removals ------------------------- - Dropped support for Python 3.5; only 3.6, 3.7 and 3.8 are supported going forward. `#23 `_ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/CONTRIBUTORS.txt0000644000175100001660000000012515031603113015552 0ustar00runnerdocker- Contributors - ---------------- Andrew Svetlov Martijn Pieters Nikolay Kim Vizonex ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/LICENSE0000644000175100001660000002610415031603113014066 0ustar00runnerdockerApache License Version 2.0, January 2004 http://www.apache.org/licenses/ TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 1. Definitions. "License" shall mean the terms and conditions for use, reproduction, and distribution as defined by Sections 1 through 9 of this document. "Licensor" shall mean the copyright owner or entity authorized by the copyright owner that is granting the License. "Legal Entity" shall mean the union of the acting entity and all other entities that control, are controlled by, or are under common control with that entity. For the purposes of this definition, "control" means (i) the power, direct or indirect, to cause the direction or management of such entity, whether by contract or otherwise, or (ii) ownership of fifty percent (50%) or more of the outstanding shares, or (iii) beneficial ownership of such entity. "You" (or "Your") shall mean an individual or Legal Entity exercising permissions granted by this License. "Source" form shall mean the preferred form for making modifications, including but not limited to software source code, documentation source, and configuration files. "Object" form shall mean any form resulting from mechanical transformation or translation of a Source form, including but not limited to compiled object code, generated documentation, and conversions to other media types. "Work" shall mean the work of authorship, whether in Source or Object form, made available under the License, as indicated by a copyright notice that is included in or attached to the work (an example is provided in the Appendix below). "Derivative Works" shall mean any work, whether in Source or Object form, that is based on (or derived from) the Work and for which the editorial revisions, annotations, elaborations, or other modifications represent, as a whole, an original work of authorship. For the purposes of this License, Derivative Works shall not include works that remain separable from, or merely link (or bind by name) to the interfaces of, the Work and Derivative Works thereof. "Contribution" shall mean any work of authorship, including the original version of the Work and any modifications or additions to that Work or Derivative Works thereof, that is intentionally submitted to Licensor for inclusion in the Work by the copyright owner or by an individual or Legal Entity authorized to submit on behalf of the copyright owner. For the purposes of this definition, "submitted" means any form of electronic, verbal, or written communication sent to the Licensor or its representatives, including but not limited to communication on electronic mailing lists, source code control systems, and issue tracking systems that are managed by, or on behalf of, the Licensor for the purpose of discussing and improving the Work, but excluding communication that is conspicuously marked or otherwise designated in writing by the copyright owner as "Not a Contribution." "Contributor" shall mean Licensor and any individual or Legal Entity on behalf of whom a Contribution has been received by Licensor and subsequently incorporated within the Work. 2. Grant of Copyright License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable copyright license to reproduce, prepare Derivative Works of, publicly display, publicly perform, sublicense, and distribute the Work and such Derivative Works in Source or Object form. 3. Grant of Patent License. Subject to the terms and conditions of this License, each Contributor hereby grants to You a perpetual, worldwide, non-exclusive, no-charge, royalty-free, irrevocable (except as stated in this section) patent license to make, have made, use, offer to sell, sell, import, and otherwise transfer the Work, where such license applies only to those patent claims licensable by such Contributor that are necessarily infringed by their Contribution(s) alone or by combination of their Contribution(s) with the Work to which such Contribution(s) was submitted. If You institute patent litigation against any entity (including a cross-claim or counterclaim in a lawsuit) alleging that the Work or a Contribution incorporated within the Work constitutes direct or contributory patent infringement, then any patent licenses granted to You under this License for that Work shall terminate as of the date such litigation is filed. 4. Redistribution. You may reproduce and distribute copies of the Work or Derivative Works thereof in any medium, with or without modifications, and in Source or Object form, provided that You meet the following conditions: (a) You must give any other recipients of the Work or Derivative Works a copy of this License; and (b) You must cause any modified files to carry prominent notices stating that You changed the files; and (c) You must retain, in the Source form of any Derivative Works that You distribute, all copyright, patent, trademark, and attribution notices from the Source form of the Work, excluding those notices that do not pertain to any part of the Derivative Works; and (d) If the Work includes a "NOTICE" text file as part of its distribution, then any Derivative Works that You distribute must include a readable copy of the attribution notices contained within such NOTICE file, excluding those notices that do not pertain to any part of the Derivative Works, in at least one of the following places: within a NOTICE text file distributed as part of the Derivative Works; within the Source form or documentation, if provided along with the Derivative Works; or, within a display generated by the Derivative Works, if and wherever such third-party notices normally appear. The contents of the NOTICE file are for informational purposes only and do not modify the License. You may add Your own attribution notices within Derivative Works that You distribute, alongside or as an addendum to the NOTICE text from the Work, provided that such additional attribution notices cannot be construed as modifying the License. You may add Your own copyright statement to Your modifications and may provide additional or different license terms and conditions for use, reproduction, or distribution of Your modifications, or for any such Derivative Works as a whole, provided Your use, reproduction, and distribution of the Work otherwise complies with the conditions stated in this License. 5. Submission of Contributions. Unless You explicitly state otherwise, any Contribution intentionally submitted for inclusion in the Work by You to the Licensor shall be under the terms and conditions of this License, without any additional terms or conditions. Notwithstanding the above, nothing herein shall supersede or modify the terms of any separate license agreement you may have executed with Licensor regarding such Contributions. 6. Trademarks. This License does not grant permission to use the trade names, trademarks, service marks, or product names of the Licensor, except as required for reasonable and customary use in describing the origin of the Work and reproducing the content of the NOTICE file. 7. Disclaimer of Warranty. Unless required by applicable law or agreed to in writing, Licensor provides the Work (and each Contributor provides its Contributions) on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied, including, without limitation, any warranties or conditions of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A PARTICULAR PURPOSE. You are solely responsible for determining the appropriateness of using or redistributing the Work and assume any risks associated with Your exercise of permissions under this License. 8. Limitation of Liability. In no event and under no legal theory, whether in tort (including negligence), contract, or otherwise, unless required by applicable law (such as deliberate and grossly negligent acts) or agreed to in writing, shall any Contributor be liable to You for damages, including any direct, indirect, special, incidental, or consequential damages of any character arising as a result of this License or out of the use or inability to use the Work (including but not limited to damages for loss of goodwill, work stoppage, computer failure or malfunction, or any and all other commercial damages or losses), even if such Contributor has been advised of the possibility of such damages. 9. Accepting Warranty or Additional Liability. While redistributing the Work or Derivative Works thereof, You may choose to offer, and charge a fee for, acceptance of support, warranty, indemnity, or other liability obligations and/or rights consistent with this License. However, in accepting such obligations, You may act only on Your own behalf and on Your sole responsibility, not on behalf of any other Contributor, and only if You agree to indemnify, defend, and hold each Contributor harmless for any liability incurred by, or claims asserted against, such Contributor by reason of your accepting any such warranty or additional liability. END OF TERMS AND CONDITIONS APPENDIX: How to apply the Apache License to your work. To apply the Apache License to your work, attach the following boilerplate notice, with the fields enclosed by brackets "{}" replaced with your own identifying information. (Don't include the brackets!) The text should be enclosed in the appropriate comment syntax for the file format. We also recommend that a file or class name and description of purpose be included on the same "printed page" as the copyright notice for easier identification within third-party archives. Copyright 2013-2019 Nikolay Kim and Andrew Svetlov Licensed under the Apache License, Version 2.0 (the "License"); you may not use this file except in compliance with the License. You may obtain a copy of the License at http://www.apache.org/licenses/LICENSE-2.0 Unless required by applicable law or agreed to in writing, software distributed under the License is distributed on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for the specific language governing permissions and limitations under the License. ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/MANIFEST.in0000644000175100001660000000044315031603113014615 0ustar00runnerdockerinclude .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 prune docs/_build ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/Makefile0000644000175100001660000000304415031603113014517 0ustar00runnerdocker# Some simple testing tasks (sorry, UNIX only). SRC = aiosignal tests setup.py all: test .install-deps: pip install -r requirements/dev.txt @touch .install-deps lint: # CI env-var is set by GitHub actions ifndef CI pre-commit run --all-files endif mypy aiosignal .develop: .install-deps $(shell find aiosignal -type f) # pip install -e . @touch .develop test: .develop @pytest -q vtest: .develop @pytest -s -v cov cover coverage: tox cov-dev: .develop @pytest -c pytest.ci.ini --cov-report=html @echo "open file://`pwd`/htmlcov/index.html" cov-ci-run: .develop @echo "Regular run" @pytest -c pytest.ci.ini --cov-report=html cov-dev-full: cov-ci-run @echo "open file://`pwd`/htmlcov/index.html" clean: @rm -rf `find . -name __pycache__` @rm -f `find . -type f -name '*.py[co]' ` @rm -f `find . -type f -name '*~' ` @rm -f `find . -type f -name '.*~' ` @rm -f `find . -type f -name '@*' ` @rm -f `find . -type f -name '#*#' ` @rm -f `find . -type f -name '*.orig' ` @rm -f `find . -type f -name '*.rej' ` @rm -f .coverage @rm -rf htmlcov @rm -rf build @rm -rf cover @make -C docs clean @python setup.py clean @rm -rf .tox @rm -f .develop @rm -f .flake @rm -f .install-deps @rm -rf aiosignal.egg-info doc: @make -C docs html SPHINXOPTS="-W -E" @echo "open file://`pwd`/docs/_build/html/index.html" doc-spelling: @make -C docs spelling SPHINXOPTS="-W -E" install: @pip install -U 'pip' @pip install -Ur requirements/dev.txt @pre-commit install install-dev: .develop .PHONY: all build flake test vtest cov clean doc mypy ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751582292.641044 aiosignal-1.4.0/PKG-INFO0000644000175100001660000000711615031603125014163 0ustar00runnerdockerMetadata-Version: 2.4 Name: aiosignal Version: 1.4.0 Summary: aiosignal: a list of registered asynchronous callbacks Home-page: https://github.com/aio-libs/aiosignal Maintainer: aiohttp team Maintainer-email: team@aiohttp.org License: Apache 2.0 Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiosignal/actions Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiosignal Project-URL: Docs: RTD, https://docs.aiosignal.org Project-URL: GitHub: issues, https://github.com/aio-libs/aiosignal/issues Project-URL: GitHub: repo, https://github.com/aio-libs/aiosignal Classifier: License :: OSI Approved :: Apache Software License Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: POSIX Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Framework :: AsyncIO Requires-Python: >=3.9 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 ========= .. image:: https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg :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?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 :target: https://pypi.org/project/aiosignal :alt: Latest PyPI package version .. image:: https://readthedocs.org/projects/aiosignal/badge/?version=latest :target: https://aiosignal.readthedocs.io/ :alt: Latest Read The Docs .. image:: https://img.shields.io/discourse/topics?server=https%3A%2F%2Faio-libs.discourse.group%2F :target: https://aio-libs.discourse.group/ :alt: Discourse group for io-libs .. image:: https://badges.gitter.im/Join%20Chat.svg :target: https://gitter.im/aio-libs/Lobby :alt: Chat on Gitter Introduction ============ A project to manage callbacks in `asyncio` projects. ``Signal`` is a list of registered asynchronous callbacks. The signal's life-cycle has two stages: after creation its content could be filled by using standard list operations: ``sig.append()`` etc. After you call ``sig.freeze()`` the signal is *frozen*: adding, removing and dropping callbacks is forbidden. The only available operation is calling the previously registered callbacks by using ``await sig.send(data)``. For concrete usage examples see the `Signals section of the `Web Server Advanced ` chapter of the `aiohttp documentation`_. Installation ------------ :: $ pip install aiosignal Documentation ============= https://aiosignal.readthedocs.io/ License ======= ``aiosignal`` is offered under the Apache 2 license. Source code =========== The project is hosted on GitHub_ Please file an issue in the `bug tracker `_ if you have found a bug or have some suggestions to improve the library. .. _GitHub: https://github.com/aio-libs/aiosignal .. _aiohttp documentation: https://docs.aiohttp.org/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/README.rst0000644000175100001660000000440315031603113014546 0ustar00runnerdocker========= aiosignal ========= .. image:: https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg :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?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 :target: https://pypi.org/project/aiosignal :alt: Latest PyPI package version .. image:: https://readthedocs.org/projects/aiosignal/badge/?version=latest :target: https://aiosignal.readthedocs.io/ :alt: Latest Read The Docs .. image:: https://img.shields.io/discourse/topics?server=https%3A%2F%2Faio-libs.discourse.group%2F :target: https://aio-libs.discourse.group/ :alt: Discourse group for io-libs .. image:: https://badges.gitter.im/Join%20Chat.svg :target: https://gitter.im/aio-libs/Lobby :alt: Chat on Gitter Introduction ============ A project to manage callbacks in `asyncio` projects. ``Signal`` is a list of registered asynchronous callbacks. The signal's life-cycle has two stages: after creation its content could be filled by using standard list operations: ``sig.append()`` etc. After you call ``sig.freeze()`` the signal is *frozen*: adding, removing and dropping callbacks is forbidden. The only available operation is calling the previously registered callbacks by using ``await sig.send(data)``. For concrete usage examples see the `Signals section of the `Web Server Advanced ` chapter of the `aiohttp documentation`_. Installation ------------ :: $ pip install aiosignal Documentation ============= https://aiosignal.readthedocs.io/ License ======= ``aiosignal`` is offered under the Apache 2 license. Source code =========== The project is hosted on GitHub_ Please file an issue in the `bug tracker `_ if you have found a bug or have some suggestions to improve the library. .. _GitHub: https://github.com/aio-libs/aiosignal .. _aiohttp documentation: https://docs.aiohttp.org/ ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751582292.6370437 aiosignal-1.4.0/aiosignal/0000755000175100001660000000000015031603125015027 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/aiosignal/__init__.py0000644000175100001660000000300115031603113017127 0ustar00runnerdockerimport sys from typing import Any, Awaitable, Callable, TypeVar from frozenlist import FrozenList 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[Callable[[Unpack[_Ts]], Awaitable[object]]]): """Coroutine-based signal implementation. To connect a callback to a signal, use any list method. Signals are fired using the send() coroutine, which takes named arguments. """ __slots__ = ("_owner",) def __init__(self, owner: object): super().__init__() self._owner = owner def __repr__(self) -> str: return "".format( self._owner, self.frozen, list(self) ) async def send(self, *args: Unpack[_Ts], **kwargs: Any) -> None: """ Sends data to all registered receivers. """ if not self.frozen: raise RuntimeError("Cannot send non-frozen signal.") for receiver in self: 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 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/aiosignal/py.typed0000644000175100001660000000000015031603113016511 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751582292.640044 aiosignal-1.4.0/aiosignal.egg-info/0000755000175100001660000000000015031603125016521 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582292.0 aiosignal-1.4.0/aiosignal.egg-info/PKG-INFO0000644000175100001660000000711615031603124017622 0ustar00runnerdockerMetadata-Version: 2.4 Name: aiosignal Version: 1.4.0 Summary: aiosignal: a list of registered asynchronous callbacks Home-page: https://github.com/aio-libs/aiosignal Maintainer: aiohttp team Maintainer-email: team@aiohttp.org License: Apache 2.0 Project-URL: Chat: Gitter, https://gitter.im/aio-libs/Lobby Project-URL: CI: GitHub Actions, https://github.com/aio-libs/aiosignal/actions Project-URL: Coverage: codecov, https://codecov.io/github/aio-libs/aiosignal Project-URL: Docs: RTD, https://docs.aiosignal.org Project-URL: GitHub: issues, https://github.com/aio-libs/aiosignal/issues Project-URL: GitHub: repo, https://github.com/aio-libs/aiosignal Classifier: License :: OSI Approved :: Apache Software License Classifier: Intended Audience :: Developers Classifier: Programming Language :: Python Classifier: Programming Language :: Python :: 3 Classifier: Programming Language :: Python :: 3 :: Only Classifier: Development Status :: 5 - Production/Stable Classifier: Operating System :: POSIX Classifier: Operating System :: MacOS :: MacOS X Classifier: Operating System :: Microsoft :: Windows Classifier: Framework :: AsyncIO Requires-Python: >=3.9 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 ========= .. image:: https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg :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?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 :target: https://pypi.org/project/aiosignal :alt: Latest PyPI package version .. image:: https://readthedocs.org/projects/aiosignal/badge/?version=latest :target: https://aiosignal.readthedocs.io/ :alt: Latest Read The Docs .. image:: https://img.shields.io/discourse/topics?server=https%3A%2F%2Faio-libs.discourse.group%2F :target: https://aio-libs.discourse.group/ :alt: Discourse group for io-libs .. image:: https://badges.gitter.im/Join%20Chat.svg :target: https://gitter.im/aio-libs/Lobby :alt: Chat on Gitter Introduction ============ A project to manage callbacks in `asyncio` projects. ``Signal`` is a list of registered asynchronous callbacks. The signal's life-cycle has two stages: after creation its content could be filled by using standard list operations: ``sig.append()`` etc. After you call ``sig.freeze()`` the signal is *frozen*: adding, removing and dropping callbacks is forbidden. The only available operation is calling the previously registered callbacks by using ``await sig.send(data)``. For concrete usage examples see the `Signals section of the `Web Server Advanced ` chapter of the `aiohttp documentation`_. Installation ------------ :: $ pip install aiosignal Documentation ============= https://aiosignal.readthedocs.io/ License ======= ``aiosignal`` is offered under the Apache 2 license. Source code =========== The project is hosted on GitHub_ Please file an issue in the `bug tracker `_ if you have found a bug or have some suggestions to improve the library. .. _GitHub: https://github.com/aio-libs/aiosignal .. _aiohttp documentation: https://docs.aiohttp.org/ ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582292.0 aiosignal-1.4.0/aiosignal.egg-info/SOURCES.txt0000644000175100001660000000123215031603124020402 0ustar00runnerdocker.codecov.yml .coveragerc CHANGES.rst CONTRIBUTORS.txt LICENSE MANIFEST.in Makefile README.rst pyproject.toml pytest.ini setup.cfg setup.py tox.ini aiosignal/__init__.py aiosignal/py.typed aiosignal.egg-info/PKG-INFO aiosignal.egg-info/SOURCES.txt aiosignal.egg-info/dependency_links.txt aiosignal.egg-info/requires.txt aiosignal.egg-info/top_level.txt docs/Makefile docs/conf.py 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././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582292.0 aiosignal-1.4.0/aiosignal.egg-info/dependency_links.txt0000644000175100001660000000000115031603124022566 0ustar00runnerdocker ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582292.0 aiosignal-1.4.0/aiosignal.egg-info/requires.txt0000644000175100001660000000010515031603124021114 0ustar00runnerdockerfrozenlist>=1.1.0 [:python_version < "3.13"] typing-extensions>=4.2 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582292.0 aiosignal-1.4.0/aiosignal.egg-info/top_level.txt0000644000175100001660000000001215031603124021243 0ustar00runnerdockeraiosignal ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751582292.6380439 aiosignal-1.4.0/docs/0000755000175100001660000000000015031603125014011 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/docs/Makefile0000644000175100001660000001534315031603113015454 0ustar00runnerdocker# Makefile for Sphinx documentation # # You can set these variables from the command line. SPHINXOPTS = SPHINXBUILD = sphinx-build PAPER = BUILDDIR = _build # User-friendly check for sphinx-build ifeq ($(shell which $(SPHINXBUILD) >/dev/null 2>&1; echo $$?), 1) $(error The '$(SPHINXBUILD)' command was not found. Make sure you have Sphinx installed, then set the SPHINXBUILD environment variable to point to the full path of the '$(SPHINXBUILD)' executable. Alternatively you can add the directory with the executable to your PATH. If you don't have Sphinx installed, grab it from http://sphinx-doc.org/) endif # Internal variables. PAPEROPT_a4 = -D latex_paper_size=a4 PAPEROPT_letter = -D latex_paper_size=letter ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . # the i18n builder cannot share the environment and doctrees with the others I18NSPHINXOPTS = $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) . .PHONY: help clean html dirhtml singlehtml pickle json htmlhelp qthelp devhelp epub latex latexpdf text man changes linkcheck doctest gettext help: @echo "Please use \`make ' where is one of" @echo " html to make standalone HTML files" @echo " dirhtml to make HTML files named index.html in directories" @echo " singlehtml to make a single large HTML file" @echo " pickle to make pickle files" @echo " json to make JSON files" @echo " htmlhelp to make HTML files and a HTML help project" @echo " qthelp to make HTML files and a qthelp project" @echo " devhelp to make HTML files and a Devhelp project" @echo " epub to make an epub" @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" @echo " latexpdf to make LaTeX files and run them through pdflatex" @echo " latexpdfja to make LaTeX files and run them through platex/dvipdfmx" @echo " text to make text files" @echo " man to make manual pages" @echo " texinfo to make Texinfo files" @echo " info to make Texinfo files and run them through makeinfo" @echo " gettext to make PO message catalogs" @echo " changes to make an overview of all changed/added/deprecated items" @echo " xml to make Docutils-native XML files" @echo " pseudoxml to make pseudoxml-XML files for display purposes" @echo " linkcheck to check all external links for integrity" @echo " doctest to run all doctests embedded in the documentation (if enabled)" clean: rm -rf $(BUILDDIR)/* html: $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." dirhtml: $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml @echo @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." singlehtml: $(SPHINXBUILD) -b singlehtml $(ALLSPHINXOPTS) $(BUILDDIR)/singlehtml @echo @echo "Build finished. The HTML page is in $(BUILDDIR)/singlehtml." pickle: $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle @echo @echo "Build finished; now you can process the pickle files." json: $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json @echo @echo "Build finished; now you can process the JSON files." htmlhelp: $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp @echo @echo "Build finished; now you can run HTML Help Workshop with the" \ ".hhp project file in $(BUILDDIR)/htmlhelp." qthelp: $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp @echo @echo "Build finished; now you can run "qcollectiongenerator" with the" \ ".qhcp project file in $(BUILDDIR)/qthelp, like this:" @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/aiosignal.qhcp" @echo "To view the help file:" @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/aiosignal.qhc" devhelp: $(SPHINXBUILD) -b devhelp $(ALLSPHINXOPTS) $(BUILDDIR)/devhelp @echo @echo "Build finished." @echo "To view the help file:" @echo "# mkdir -p $$HOME/.local/share/devhelp/aiosignal" @echo "# ln -s $(BUILDDIR)/devhelp $$HOME/.local/share/devhelp/aiosignal" @echo "# devhelp" epub: $(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) $(BUILDDIR)/epub @echo @echo "Build finished. The epub file is in $(BUILDDIR)/epub." latex: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." @echo "Run \`make' in that directory to run these through (pdf)latex" \ "(use \`make latexpdf' here to do that automatically)." latexpdf: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through pdflatex..." $(MAKE) -C $(BUILDDIR)/latex all-pdf @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." latexpdfja: $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex @echo "Running LaTeX files through platex and dvipdfmx..." $(MAKE) -C $(BUILDDIR)/latex all-pdf-ja @echo "pdflatex finished; the PDF files are in $(BUILDDIR)/latex." text: $(SPHINXBUILD) -b text $(ALLSPHINXOPTS) $(BUILDDIR)/text @echo @echo "Build finished. The text files are in $(BUILDDIR)/text." man: $(SPHINXBUILD) -b man $(ALLSPHINXOPTS) $(BUILDDIR)/man @echo @echo "Build finished. The manual pages are in $(BUILDDIR)/man." texinfo: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo @echo "Build finished. The Texinfo files are in $(BUILDDIR)/texinfo." @echo "Run \`make' in that directory to run these through makeinfo" \ "(use \`make info' here to do that automatically)." info: $(SPHINXBUILD) -b texinfo $(ALLSPHINXOPTS) $(BUILDDIR)/texinfo @echo "Running Texinfo files through makeinfo..." make -C $(BUILDDIR)/texinfo info @echo "makeinfo finished; the Info files are in $(BUILDDIR)/texinfo." gettext: $(SPHINXBUILD) -b gettext $(I18NSPHINXOPTS) $(BUILDDIR)/locale @echo @echo "Build finished. The message catalogs are in $(BUILDDIR)/locale." changes: $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes @echo @echo "The overview file is in $(BUILDDIR)/changes." linkcheck: $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck @echo @echo "Link check complete; look for any errors in the above output " \ "or in $(BUILDDIR)/linkcheck/output.txt." doctest: $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest @echo "Testing of doctests in the sources finished, look at the " \ "results in $(BUILDDIR)/doctest/output.txt." xml: $(SPHINXBUILD) -b xml $(ALLSPHINXOPTS) $(BUILDDIR)/xml @echo @echo "Build finished. The XML files are in $(BUILDDIR)/xml." pseudoxml: $(SPHINXBUILD) -b pseudoxml $(ALLSPHINXOPTS) $(BUILDDIR)/pseudoxml @echo @echo "Build finished. The pseudo-XML files are in $(BUILDDIR)/pseudoxml." spelling: $(SPHINXBUILD) -b spelling $(ALLSPHINXOPTS) $(BUILDDIR)/spelling @echo @echo "Build finished." ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/docs/conf.py0000644000175100001660000002540215031603113015310 0ustar00runnerdocker#!/usr/bin/env python3 # # aiosignal documentation build configuration file, created by # sphinx-quickstart on Wed Mar 5 12:35:35 2014. # # This file is execfile()d with the current directory set to its # containing dir. # # Note that not all possible configuration values are present in this # autogenerated file. # # All configuration values have a default; values that are commented out # serve to show the default. import os import re _docs_path = os.path.dirname(__file__) _version_path = os.path.abspath( os.path.join(_docs_path, "..", "aiosignal", "__init__.py") ) with open(_version_path, encoding="latin1") as fp: try: _version_info = re.search( r'^__version__ = "' r"(?P\d+)" r"\.(?P\d+)" r"\.(?P\d+)" r'(?P.*)?"$', fp.read(), re.M, ).groupdict() except IndexError: raise RuntimeError("Unable to determine version.") # -- General configuration ------------------------------------------------ # If your documentation needs a minimal Sphinx version, state it here. # needs_sphinx = '1.0' # Add any Sphinx extension module names here, as strings. They can be # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom # ones. extensions = [ "sphinx.ext.viewcode", "sphinx.ext.intersphinx", ] try: import sphinxcontrib.spelling # noqa extensions.append("sphinxcontrib.spelling") except ImportError: pass intersphinx_mapping = { "python": ("http://docs.python.org/3", None), "aiohttp": ("https://docs.aiohttp.org/en/stable/", None), "frozenlist": ("https://frozenlist.readthedocs.io/en/latest/", None), } # Add any paths that contain templates here, relative to this directory. templates_path = ["_templates"] # The suffix of source filenames. source_suffix = ".rst" # The encoding of source files. # source_encoding = 'utf-8-sig' # The master toctree document. master_doc = "index" # General information about the project. project = "aiosignal" copyright = "2013-2019, aiosignal contributors" # The version info for the project you're documenting, acts as replacement for # |version| and |release|, also used in various other places throughout the # built documents. # # The short X.Y version. version = "{major}.{minor}".format(**_version_info) # The full version, including alpha/beta/rc tags. release = "{major}.{minor}.{patch}{tag}".format(**_version_info) # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. # language = None # There are two options for replacing |today|: either, you set today to some # non-false value, then it is used: # today = '' # Else, today_fmt is used as the format for a strftime call. # today_fmt = '%B %d, %Y' # List of patterns, relative to source directory, that match files and # directories to ignore when looking for source files. exclude_patterns = ["_build"] # The reST default role (used for this markup: `text`) to use for all # documents. # default_role = None # If true, '()' will be appended to :func: etc. cross-reference text. # add_function_parentheses = True # If true, the current module name will be prepended to all description # unit titles (such as .. function::). # add_module_names = True # If true, sectionauthor and moduleauthor directives will be shown in the # output. They are ignored by default. # show_authors = False # The name of the Pygments (syntax highlighting) style to use. # pygments_style = 'sphinx' # The default language to highlight source code in. highlight_language = "python3" # A list of ignored prefixes for module index sorting. # modindex_common_prefix = [] # If true, keep warnings as "system message" paragraphs in the built documents. # keep_warnings = False # -- Options for HTML output ---------------------------------------------- # The theme to use for HTML and HTML Help pages. See the documentation for # a list of builtin themes. html_theme = "aiohttp_theme" # Theme options are theme-specific and customize the look and feel of a theme # further. For a list of options available for each theme, see the # documentation. html_theme_options = { "logo": None, "description": "aiosignal: a list of registered asynchronous callbacks.", "canonical_url": "http://aiosignal.readthedocs.io/en/stable/", "github_user": "aio-libs", "github_repo": "aiosignal", "github_button": True, "github_type": "star", "github_banner": True, "badges": [ { "image": "https://github.com/aio-libs/aiosignal/workflows/CI/badge.svg", "target": ( "https://github.com/aio-libs/aiosignal/" "actions?query=workflow%3ACI" ), "height": "20", "alt": "GitHub CI status for master branch", }, { "image": ( "https://codecov.io/github/aio-libs/aiosignal/" "coverage.svg?branch=master" ), "target": "https://codecov.io/github/aio-libs/aiosignal", "height": "20", "alt": "Code coverage status", }, { "image": "https://badge.fury.io/py/aiosignal.svg", "target": "https://badge.fury.io/py/aiosignal", "height": "20", "alt": "Latest PyPI package version", }, { "image": ( "https://img.shields.io/discourse/" "topics?server=https%3A%2F%2Faio-libs.discourse.group%2F" ), "target": "https://aio-libs.discourse.group/", "height": "20", "alt": "Discourse group for io-libs", }, { "image": "https://badges.gitter.im/Join%20Chat.svg", "target": "https://gitter.im/aio-libs/Lobby", "height": "20", "alt": "Chat on Gitter", }, ], } # Add any paths that contain custom themes here, relative to this directory. # html_theme_path = [alabaster.get_path()] # The name for this set of Sphinx documents. If None, it defaults to # " v documentation". # html_title = None # A shorter title for the navigation bar. Default is the same as html_title. # html_short_title = None # The name of an image file (relative to this directory) to place at the top # of the sidebar. # html_logo = 'aiosignal-icon.svg' # The name of an image file (within the static path) to use as favicon of the # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 # pixels large. # html_favicon = 'favicon.ico' # Add any paths that contain custom static files (such as style sheets) here, # relative to this directory. They are copied after the builtin static files, # so a file named "default.css" will overwrite the builtin "default.css". # html_static_path = [] # Add any extra paths that contain custom files (such as robots.txt or # .htaccess) here, relative to this directory. These files are copied # directly to the root of the documentation. # html_extra_path = [] # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, # using the given strftime format. # html_last_updated_fmt = '%b %d, %Y' # If true, SmartyPants will be used to convert quotes and dashes to # typographically correct entities. # html_use_smartypants = True # Custom sidebar templates, maps document names to template names. html_sidebars = { "**": [ "about.html", "navigation.html", "searchbox.html", ] } # Additional templates that should be rendered to pages, maps page names to # template names. # html_additional_pages = {} # If false, no module index is generated. # html_domain_indices = True # If false, no index is generated. # html_use_index = True # If true, the index is split into individual pages for each letter. # html_split_index = False # If true, links to the reST sources are added to the pages. # html_show_sourcelink = True # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. # html_show_sphinx = True # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. # html_show_copyright = True # If true, an OpenSearch description file will be output, and all pages will # contain a tag referring to it. The value of this option must be the # base URL from which the finished HTML is served. # html_use_opensearch = '' # This is the file name suffix for HTML files (e.g. ".xhtml"). # html_file_suffix = None # Output file base name for HTML help builder. htmlhelp_basename = "aiosignaldoc" # -- Options for LaTeX output --------------------------------------------- latex_elements = { # The paper size ('letterpaper' or 'a4paper'). # 'papersize': 'letterpaper', # The font size ('10pt', '11pt' or '12pt'). # 'pointsize': '10pt', # Additional stuff for the LaTeX preamble. # 'preamble': '', } # Grouping the document tree into LaTeX files. List of tuples # (source start file, target name, title, # author, documentclass [howto, manual, or own class]). latex_documents = [ ( "index", "aiosignal.tex", "aiosignal Documentation", "aiosignal contributors", "manual", ), ] # The name of an image file (relative to this directory) to place at the top of # the title page. # latex_logo = None # For "manual" documents, if this is true, then toplevel headings are parts, # not chapters. # latex_use_parts = False # If true, show page references after internal links. # latex_show_pagerefs = False # If true, show URL addresses after external links. # latex_show_urls = False # Documents to append as an appendix to all manuals. # latex_appendices = [] # If false, no module index is generated. # latex_domain_indices = True # -- Options for manual page output --------------------------------------- # One entry per manual page. List of tuples # (source start file, name, description, authors, manual section). man_pages = [("index", "aiosignal", "aiosignal Documentation", ["aiosignal"], 1)] # If true, show URL addresses after external links. # man_show_urls = False # -- Options for Texinfo output ------------------------------------------- # Grouping the document tree into Texinfo files. List of tuples # (source start file, target name, title, author, # dir menu entry, description, category) texinfo_documents = [ ( "index", "aiosignal", "aiosignal Documentation", "aiosignal contributors", "aiosignal", "One line description of project.", "Miscellaneous", ), ] # Documents to append as an appendix to all manuals. # texinfo_appendices = [] # If false, no module index is generated. # texinfo_domain_indices = True # How to display URL addresses: 'footnote', 'no', or 'inline'. # texinfo_show_urls = 'footnote' # If true, do not generate a @detailmenu in the "Top" node's menu. # texinfo_no_detailmenu = False ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/docs/index.rst0000644000175100001660000000537215031603113015656 0ustar00runnerdockeraiosignal ========= A project to manage callbacks in `asyncio` projects. ``Signal`` is a list of registered asynchronous callbacks. The signal's life-cycle has two stages: after creation its content could be filled by using standard list operations: ``sig.append()`` etc. After you call ``sig.freeze()`` the signal is *frozen*: adding, removing and dropping callbacks is forbidden. 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 `. API --- .. class:: aiosignal.Signal(owner) The signal, implements the :class:`collections.abc.MutableSequence` interface. The *owner* object is shown in the signal representation, and is there to make debugging easier. .. method:: send(*args, **kwargs) :async: Call all registered callbacks one by one starting from the beginning of the list. .. attribute:: frozen ``True`` if :meth:`freeze` was called, read-only property. .. method:: freeze() Freeze the list. After calling, any content modification is forbidden. Installation ------------ .. code-block:: bash $ pip install aiosignal The library requires Python 3.8 or newer. Dependencies ------------ aiosignal depends on the frozenlist_ library. Documentation ============= https://aiosignal.readthedocs.io/ Communication channels ====================== *aio-libs discourse group*: https://aio-libs.discourse.group Feel free to post your questions and ideas here. *gitter chat* https://gitter.im/aio-libs/Lobby Requirements ============ - Python >= 3.8 - frozenlist >= 1.0.0 License ======= ``aiosignal`` is offered under the Apache 2 license. Source code =========== The project is hosted on GitHub_ Please file an issue in the `bug tracker `_ if you have found a bug or have some suggestions to improve the library. Authors and License =================== The ``aiosignal`` package was originally part of the :doc:`aiohttp project `, written by Nikolay Kim and Andrew Svetlov. It is now being maintained by Martijn Pieters. It's *Apache 2* licensed and freely available. Feel free to improve this package and send a pull request to GitHub_. .. toctree:: :maxdepth: 2 Indices and tables ================== * :ref:`genindex` * :ref:`search` .. _GitHub: https://github.com/aio-libs/aiosignal .. _frozenlist: https://github.com/aio-libs/frozenlist ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/docs/make.bat0000644000175100001660000001506315031603113015420 0ustar00runnerdocker@ECHO OFF REM Command file for Sphinx documentation if "%SPHINXBUILD%" == "" ( set SPHINXBUILD=sphinx-build ) set BUILDDIR=_build set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% . set I18NSPHINXOPTS=%SPHINXOPTS% . if NOT "%PAPER%" == "" ( set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% set I18NSPHINXOPTS=-D latex_paper_size=%PAPER% %I18NSPHINXOPTS% ) if "%1" == "" goto help if "%1" == "help" ( :help echo.Please use `make ^` where ^ is one of echo. html to make standalone HTML files echo. dirhtml to make HTML files named index.html in directories echo. singlehtml to make a single large HTML file echo. pickle to make pickle files echo. json to make JSON files echo. htmlhelp to make HTML files and a HTML help project echo. qthelp to make HTML files and a qthelp project echo. devhelp to make HTML files and a Devhelp project echo. epub to make an epub echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter echo. text to make text files echo. man to make manual pages echo. texinfo to make Texinfo files echo. gettext to make PO message catalogs echo. changes to make an overview over all changed/added/deprecated items echo. xml to make Docutils-native XML files echo. pseudoxml to make pseudoxml-XML files for display purposes echo. linkcheck to check all external links for integrity echo. doctest to run all doctests embedded in the documentation if enabled goto end ) if "%1" == "clean" ( for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i del /q /s %BUILDDIR%\* goto end ) %SPHINXBUILD% 2> nul if errorlevel 9009 ( echo. echo.The 'sphinx-build' command was not found. Make sure you have Sphinx echo.installed, then set the SPHINXBUILD environment variable to point echo.to the full path of the 'sphinx-build' executable. Alternatively you echo.may add the Sphinx directory to PATH. echo. echo.If you don't have Sphinx installed, grab it from echo.http://sphinx-doc.org/ exit /b 1 ) if "%1" == "html" ( %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/html. goto end ) if "%1" == "dirhtml" ( %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. goto end ) if "%1" == "singlehtml" ( %SPHINXBUILD% -b singlehtml %ALLSPHINXOPTS% %BUILDDIR%/singlehtml if errorlevel 1 exit /b 1 echo. echo.Build finished. The HTML pages are in %BUILDDIR%/singlehtml. goto end ) if "%1" == "pickle" ( %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the pickle files. goto end ) if "%1" == "json" ( %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can process the JSON files. goto end ) if "%1" == "htmlhelp" ( %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run HTML Help Workshop with the ^ .hhp project file in %BUILDDIR%/htmlhelp. goto end ) if "%1" == "qthelp" ( %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp if errorlevel 1 exit /b 1 echo. echo.Build finished; now you can run "qcollectiongenerator" with the ^ .qhcp project file in %BUILDDIR%/qthelp, like this: echo.^> qcollectiongenerator %BUILDDIR%\qthelp\aiosignal.qhcp echo.To view the help file: echo.^> assistant -collectionFile %BUILDDIR%\qthelp\aiosignal.ghc goto end ) if "%1" == "devhelp" ( %SPHINXBUILD% -b devhelp %ALLSPHINXOPTS% %BUILDDIR%/devhelp if errorlevel 1 exit /b 1 echo. echo.Build finished. goto end ) if "%1" == "epub" ( %SPHINXBUILD% -b epub %ALLSPHINXOPTS% %BUILDDIR%/epub if errorlevel 1 exit /b 1 echo. echo.Build finished. The epub file is in %BUILDDIR%/epub. goto end ) if "%1" == "latex" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex if errorlevel 1 exit /b 1 echo. echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdf" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "latexpdfja" ( %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex cd %BUILDDIR%/latex make all-pdf-ja cd %BUILDDIR%/.. echo. echo.Build finished; the PDF files are in %BUILDDIR%/latex. goto end ) if "%1" == "text" ( %SPHINXBUILD% -b text %ALLSPHINXOPTS% %BUILDDIR%/text if errorlevel 1 exit /b 1 echo. echo.Build finished. The text files are in %BUILDDIR%/text. goto end ) if "%1" == "man" ( %SPHINXBUILD% -b man %ALLSPHINXOPTS% %BUILDDIR%/man if errorlevel 1 exit /b 1 echo. echo.Build finished. The manual pages are in %BUILDDIR%/man. goto end ) if "%1" == "texinfo" ( %SPHINXBUILD% -b texinfo %ALLSPHINXOPTS% %BUILDDIR%/texinfo if errorlevel 1 exit /b 1 echo. echo.Build finished. The Texinfo files are in %BUILDDIR%/texinfo. goto end ) if "%1" == "gettext" ( %SPHINXBUILD% -b gettext %I18NSPHINXOPTS% %BUILDDIR%/locale if errorlevel 1 exit /b 1 echo. echo.Build finished. The message catalogs are in %BUILDDIR%/locale. goto end ) if "%1" == "changes" ( %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes if errorlevel 1 exit /b 1 echo. echo.The overview file is in %BUILDDIR%/changes. goto end ) if "%1" == "linkcheck" ( %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck if errorlevel 1 exit /b 1 echo. echo.Link check complete; look for any errors in the above output ^ or in %BUILDDIR%/linkcheck/output.txt. goto end ) if "%1" == "doctest" ( %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest if errorlevel 1 exit /b 1 echo. echo.Testing of doctests in the sources finished, look at the ^ results in %BUILDDIR%/doctest/output.txt. goto end ) if "%1" == "xml" ( %SPHINXBUILD% -b xml %ALLSPHINXOPTS% %BUILDDIR%/xml if errorlevel 1 exit /b 1 echo. echo.Build finished. The XML files are in %BUILDDIR%/xml. goto end ) if "%1" == "pseudoxml" ( %SPHINXBUILD% -b pseudoxml %ALLSPHINXOPTS% %BUILDDIR%/pseudoxml if errorlevel 1 exit /b 1 echo. echo.Build finished. The pseudo-XML files are in %BUILDDIR%/pseudoxml. goto end ) :end ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/docs/spelling_wordlist.txt0000644000175100001660000000513215031603113020314 0ustar00runnerdockerabc aiodns aioes aiohttp aiohttpdemo aiohttp’s aiopg alives api api’s app apps app’s arg Arsenic async asyncio auth autocalculated autodetection autogenerates autogeneration awaitable backend backends Backport Backporting backport backports BaseEventLoop basename BasicAuth BodyPartReader boolean botocore Bugfixes builtin bugfix BytesIO cchardet cChardet Changelog charset charsetdetect chunked chunking CIMultiDict ClientSession cls cmd codec Codings committer committers config Config configs conjunction contextmanager CookieJar coroutine Coroutine coroutines cpu CPython css ctor Ctrl de deduplicate # de-facto: deprecations DER Dev dict Dict Discord django Django dns DNSResolver docstring Dup elasticsearch encodings env environ eof epoll Facebook facto fallback fallbacks filename finalizers frontend getall gethostbyname github google gunicorn gunicorn’s gzipped hackish highlevel hostnames HTTPException HttpProcessingError httpretty https impl incapsulates Indices infos initializer inline intaking io ip IP ipdb IPv ish iterable iterables javascript Jinja json keepalive keepalived keepalives keepaliving kwarg latin linux localhost Locator login lookup lookups lossless Mako Martijn manylinux metadata microservice middleware middlewares miltidict misbehaviors misformed Mixcloud Mongo msg MsgType multi multidict multidicts multidict’s Multidicts multipart Multipart Nagle Nagle’s namedtuple nameservers namespace nginx Nginx Nikolay noop nowait OAuth Online optimizations os outcoming Overridable Paolini param params pathlib peername Pieters ping pipelining pluggable plugin poller pong Postgres pre programmatically proxied PRs pubsub Punycode py pyenv pyflakes pytest Pytest Quickstart quote’s readonly readpayload rebase redirections Redis refactor Refactor refactored refactoring regex regexps regexs reloader renderer renderers repo repr repr’s RequestContextManager request’s Request’s requote requoting resolvehost resolvers reusage reuseconn Runit sa Satisfiable schemas sendfile serializable shourtcuts skipuntil Skyscanner SocketSocketTransport ssl SSLContext startup subapplication subclasses submodules subpackage subprotocol subprotocols subtype supervisord Supervisord Svetlov symlink symlinks syscall syscalls Systemd tarball TCP TLS teardown Teardown TestClient Testsuite Tf timestamps toolbar toplevel towncrier tp tuples UI un unawaited unclosed unicode unittest Unittest unix unsets unstripped upstr url urldispatcher urlencoded urls url’s utf utils uvloop vcvarsall waituntil webapp websocket websockets websocket’s Websockets wildcard Workflow ws wsgi WSMessage WSMsgType wss www xxx yarl ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/pyproject.toml0000644000175100001660000000053015031603113015770 0ustar00runnerdocker[build-system] requires = [ "setuptools>=51.0", ] build-backend = "setuptools.build_meta" [tool.towncrier] package = "aiosignal" filename = "CHANGES.rst" directory = "CHANGES/" title_format = "{version} ({project_date})" template = "CHANGES/.TEMPLATE.rst" issue_format = "`#{issue} `_" ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/pytest.ini0000644000175100001660000000343415031603113015113 0ustar00runnerdocker[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 ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751582292.640044 aiosignal-1.4.0/requirements/0000755000175100001660000000000015031603125015604 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/ci-bot.txt0000644000175100001660000000002515031603113017514 0ustar00runnerdocker-r ci-wheel.txt -e . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/ci-wheel.txt0000644000175100001660000000007415031603113020040 0ustar00runnerdocker-r wheel.txt coverage==7.9.1 pytest-cov==6.2.1 tox==4.27.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/ci.txt0000644000175100001660000000023115031603113016731 0ustar00runnerdockersetuptools-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 . ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/dev.txt0000644000175100001660000000006015031603113017114 0ustar00runnerdocker-r ci.txt -r towncrier.txt cherry_picker==2.5.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/doc-spelling.txt0000644000175100001660000000014415031603113020721 0ustar00runnerdocker-r doc.txt sphinxcontrib-spelling==8.0.1; platform_system!="Windows" # We only use it in Travis CI ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/doc.txt0000644000175100001660000000006115031603113017104 0ustar00runnerdockersphinx==8.2.3 pygments>=2.1 aiohttp-theme==0.1.7 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/towncrier.txt0000644000175100001660000000002215031603113020350 0ustar00runnerdockertowncrier==24.8.0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/requirements/wheel.txt0000644000175100001660000000010315031603113017440 0ustar00runnerdockerpytest==8.4.1 pytest-asyncio==1.0.0 pre-commit==4.2.0 twine==6.1.0 ././@PaxHeader0000000000000000000000000000003400000000000010212 xustar0028 mtime=1751582292.6420438 aiosignal-1.4.0/setup.cfg0000644000175100001660000000334015031603125014702 0ustar00runnerdocker[metadata] name = aiosignal version = attr: aiosignal.__version__ url = https://github.com/aio-libs/aiosignal project_urls = Chat: Gitter = https://gitter.im/aio-libs/Lobby CI: GitHub Actions = https://github.com/aio-libs/aiosignal/actions Coverage: codecov = https://codecov.io/github/aio-libs/aiosignal Docs: RTD = https://docs.aiosignal.org GitHub: issues = https://github.com/aio-libs/aiosignal/issues GitHub: repo = https://github.com/aio-libs/aiosignal description = aiosignal: a list of registered asynchronous callbacks long_description = file: README.rst long_description_content_type = text/x-rst maintainer = aiohttp team maintainer_email = team@aiohttp.org license = Apache 2.0 license_file = LICENSE classifiers = License :: OSI Approved :: Apache Software License Intended Audience :: Developers Programming Language :: Python Programming Language :: Python :: 3 Programming Language :: Python :: 3 :: Only Development Status :: 5 - Production/Stable Operating System :: POSIX Operating System :: MacOS :: MacOS X Operating System :: Microsoft :: Windows Framework :: AsyncIO [options] python_requires = >=3.9 packages = find: include_package_data = True install_requires = frozenlist >= 1.1.0 typing-extensions >= 4.2; python_version < '3.13' [pep8] max-line-length = 88 [easy_install] zip_ok = false [flake8] ignore = N801,N802,N803,E203,E226,E305,W504,E252,E301,E302,E704,W503,W504,F811 max-line-length = 88 [isort] line_length = 88 include_trailing_comma = True multi_line_output = 3 force_grid_wrap = 0 combine_as_imports = True known_third_party = pytest known_first_party = aiosignal [report] exclude_lines = @abc.abstractmethod @abstractmethod [egg_info] tag_build = tag_date = 0 ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/setup.py0000644000175100001660000000010515031603113014564 0ustar00runnerdockerfrom setuptools import setup if __name__ == "__main__": setup() ././@PaxHeader0000000000000000000000000000003300000000000010211 xustar0027 mtime=1751582292.640044 aiosignal-1.4.0/tests/0000755000175100001660000000000015031603125014223 5ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/tests/conftest.py0000644000175100001660000000000015031603113016405 0ustar00runnerdocker././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/tests/test_signals.py0000644000175100001660000001014515031603113017272 0ustar00runnerdockerimport 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: return "" @pytest.fixture def owner() -> Owner: return Owner() 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) # type: ignore[arg-type] signal.freeze() with pytest.raises(TypeError): await signal.send() 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: object) -> None: callback_mock(**kwargs) signal.append(callback) signal.freeze() await signal.send(**kwargs) callback_mock.assert_called_once_with(**kwargs) async def test_function_signal_dispatch_args_kwargs(owner: Owner) -> None: signal = Signal[Unpack[tuple[str, ...]]](owner) kwargs = {"foo": 1, "bar": 2} callback_mock = mock.Mock() async def callback(*args: str, **kwargs: object) -> None: callback_mock(*args, **kwargs) signal.append(callback) signal.freeze() await signal.send("a", "b", **kwargs) callback_mock.assert_called_once_with("a", "b", **kwargs) async def test_non_coroutine(owner: Owner) -> None: signal = Signal(owner) kwargs = {"foo": 1, "bar": 2} callback = mock.Mock() signal.append(callback) signal.freeze() with pytest.raises(TypeError): await signal.send(**kwargs) def test_setitem(owner: Owner) -> None: signal = Signal(owner) m1 = mock.Mock() signal.append(m1) assert signal[0] is m1 m2 = mock.Mock() signal[0] = m2 assert signal[0] is m2 def test_delitem(owner: Owner) -> None: signal = Signal(owner) m1 = mock.Mock() signal.append(m1) assert len(signal) == 1 del signal[0] assert len(signal) == 0 def test_cannot_append_to_frozen_signal(owner: Owner) -> None: signal = Signal(owner) m1 = mock.Mock() m2 = mock.Mock() signal.append(m1) signal.freeze() with pytest.raises(RuntimeError): signal.append(m2) assert list(signal) == [m1] def test_cannot_setitem_in_frozen_signal(owner: Owner) -> None: signal = Signal(owner) m1 = mock.Mock() m2 = mock.Mock() signal.append(m1) signal.freeze() with pytest.raises(RuntimeError): signal[0] = m2 assert list(signal) == [m1] def test_cannot_delitem_in_frozen_signal(owner: Owner) -> None: signal = Signal(owner) m1 = mock.Mock() signal.append(m1) signal.freeze() with pytest.raises(RuntimeError): del signal[0] assert list(signal) == [m1] async def test_cannot_send_non_frozen_signal(owner: Owner) -> None: signal = Signal(owner) callback_mock = mock.Mock() async def callback(**kwargs: object) -> None: callback_mock(**kwargs) # pragma: no cover # mustn't be called signal.append(callback) with pytest.raises(RuntimeError): await signal.send() assert not callback_mock.called def test_repr(owner: Owner) -> None: signal = Signal(owner) signal.append(mock.Mock(__repr__=lambda *a: "")) assert ( re.match( r", frozen=False, " r"\[\]>", repr(signal), ) 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) ././@PaxHeader0000000000000000000000000000002600000000000010213 xustar0022 mtime=1751582283.0 aiosignal-1.4.0/tox.ini0000644000175100001660000003142515031603113014376 0ustar00runnerdocker[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 =