diff --git a/.github/workflows/python-package.yml b/.github/workflows/python-package.yml index 2d15da0..42b8e10 100644 --- a/.github/workflows/python-package.yml +++ b/.github/workflows/python-package.yml @@ -14,7 +14,7 @@ jobs: runs-on: ubuntu-latest strategy: matrix: - python-version: ["3.11", "3.12"] + python-version: ["3.10", "3.11", "3.12"] steps: - uses: actions/checkout@v2 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 4a3e61a..d1655a0 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -14,5 +14,5 @@ repos: language: node pass_filenames: false types: [python] - additional_dependencies: ["pyright@1.1.364"] + additional_dependencies: ["pyright@1.1.382"] repo: local diff --git a/README.md b/README.md index d6896c1..1a261fc 100644 --- a/README.md +++ b/README.md @@ -2,12 +2,12 @@ drawing # aioreactive - ReactiveX for asyncio using async and await + [![PyPI](https://img.shields.io/pypi/v/aioreactive.svg)](https://pypi.python.org/pypi/aioreactive) ![Python package](https://github.com/dbrattli/aioreactive/workflows/Python%20package/badge.svg) ![Publish Package](https://github.com/dbrattli/aioreactive/actions/workflows/python-publish.yml/badge.svg) [![codecov](https://codecov.io/gh/dbrattli/aioreactive/branch/master/graph/badge.svg)](https://codecov.io/gh/dbrattli/aioreactive) - > *NEWS: Project rebooted Nov. 2020. Rebuilt using [Expression](https://github.com/dbrattli/Expression).* Aioreactive is [RxPY](https://github.com/ReactiveX/RxPY) for asyncio. @@ -19,9 +19,9 @@ and, integrates naturally with the Python language. > aioreactive is the unification of RxPY and reactive programming with > asyncio using async and await. -## The design goals for aioreactive: +## The design goals for aioreactive -* Python 3.11+ only. We have a hard dependency [Expression v5]([https://www.python.org/dev/peps/pep-0585/](https://github.com/dbrattli/Expression)). +* Python 3.10+ only. We have a hard dependency [Expression v5]([https://www.python.org/dev/peps/pep-0585/](https://github.com/dbrattli/Expression)). * All operators and tools are implemented as plain old functions. * Everything is `async`. Sending values is async, subscribing to observables is async. Disposing subscriptions is async. diff --git a/aioreactive/__init__.py b/aioreactive/__init__.py index 5a059b5..3e1bb69 100644 --- a/aioreactive/__init__.py +++ b/aioreactive/__init__.py @@ -1,6 +1,6 @@ """Aioreactive module. -Contains the AsyncRx chained obserable that allows method chaining of all operators. +Contains the AsyncRx chained observable that allows method chaining of all operators. Also contains all operators as plain functions. @@ -16,11 +16,11 @@ from __future__ import annotations from collections.abc import AsyncIterable, Awaitable, Callable, Iterable -from typing import Any, TypeVar, TypeVarTuple +from typing import Any, TypeVar from expression import Option, curry_flip, pipe from expression.system.disposable import AsyncDisposable -from typing_extensions import Unpack +from typing_extensions import TypeVarTuple, Unpack from .observables import AsyncAnonymousObservable, AsyncIterableObservable from .observers import ( diff --git a/aioreactive/timeshift.py b/aioreactive/timeshift.py index b5b1f94..913a643 100644 --- a/aioreactive/timeshift.py +++ b/aioreactive/timeshift.py @@ -1,7 +1,7 @@ import asyncio import logging from collections.abc import Awaitable, Callable, Iterable -from datetime import UTC, datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import NoReturn, TypeVar from expression import curry_flipped @@ -59,7 +59,7 @@ async def loop() -> TailCallResult[None, ...]: ns, due_time = await inbox.receive() - diff = due_time - datetime.now(UTC) + diff = due_time - datetime.now(timezone.utc) seconds = diff.total_seconds() if seconds > 0: await asyncio.sleep(seconds) @@ -84,7 +84,7 @@ async def matcher() -> None: agent = MailboxProcessor.start(worker, token) async def fn(ns: Notification[_TSource]) -> None: - due_time = datetime.now(UTC) + timedelta(seconds=seconds) + due_time = datetime.now(timezone.utc) + timedelta(seconds=seconds) agent.post((ns, due_time)) obv: AsyncNotificationObserver[_TSource] = AsyncNotificationObserver(fn) diff --git a/poetry.lock b/poetry.lock index 565abe5..59445f5 100644 --- a/poetry.lock +++ b/poetry.lock @@ -1,28 +1,14 @@ -# This file is automatically @generated by Poetry 1.8.2 and should not be changed by hand. - -[[package]] -name = "autoflake" -version = "1.7.8" -description = "Removes unused imports and unused variables" -optional = false -python-versions = ">=3.7" -files = [ - {file = "autoflake-1.7.8-py3-none-any.whl", hash = "sha256:46373ef69b6714f5064c923bb28bd797c4f8a9497f557d87fc36665c6d956b39"}, - {file = "autoflake-1.7.8.tar.gz", hash = "sha256:e7e46372dee46fa1c97acf310d99d922b63d369718a270809d7c278d34a194cf"}, -] - -[package.dependencies] -pyflakes = ">=1.1.0,<3" +# This file is automatically @generated by Poetry 1.8.3 and should not be changed by hand. [[package]] name = "certifi" -version = "2023.11.17" +version = "2024.8.30" description = "Python package for providing Mozilla's CA Bundle." optional = false python-versions = ">=3.6" files = [ - {file = "certifi-2023.11.17-py3-none-any.whl", hash = "sha256:e036ab49d5b79556f99cfc2d9320b34cfbe5be05c5871b51de9329f0603b0474"}, - {file = "certifi-2023.11.17.tar.gz", hash = "sha256:9b469f3a900bf28dc19b8cfbf8019bf47f7fdd1a65a1d4ffb98fc14166beb4d1"}, + {file = "certifi-2024.8.30-py3-none-any.whl", hash = "sha256:922820b53db7a7257ffbda3f597266d435245903d80737e34f8a45ff3e3230d8"}, + {file = "certifi-2024.8.30.tar.gz", hash = "sha256:bec941d2aa8195e248a60b31ff9f0558284cf01a52591ceda73ea9afffd69fd9"}, ] [[package]] @@ -250,61 +236,75 @@ files = [ [[package]] name = "dunamai" -version = "1.19.0" +version = "1.22.0" description = "Dynamic version generation" optional = false -python-versions = ">=3.5,<4.0" +python-versions = ">=3.5" files = [ - {file = "dunamai-1.19.0-py3-none-any.whl", hash = "sha256:1ed948676bbf0812bfaafe315a134634f8d6eb67138513c75aa66e747404b9c6"}, - {file = "dunamai-1.19.0.tar.gz", hash = "sha256:6ad99ae34f7cd290550a2ef1305d2e0292e6e6b5b1b830dfc07ceb7fd35fec09"}, + {file = "dunamai-1.22.0-py3-none-any.whl", hash = "sha256:eab3894b31e145bd028a74b13491c57db01986a7510482c9b5fff3b4e53d77b7"}, + {file = "dunamai-1.22.0.tar.gz", hash = "sha256:375a0b21309336f0d8b6bbaea3e038c36f462318c68795166e31f9873fdad676"}, ] [package.dependencies] packaging = ">=20.9" +[[package]] +name = "exceptiongroup" +version = "1.2.2" +description = "Backport of PEP 654 (exception groups)" +optional = false +python-versions = ">=3.7" +files = [ + {file = "exceptiongroup-1.2.2-py3-none-any.whl", hash = "sha256:3111b9d131c238bec2f8f516e123e14ba243563fb135d3fe885990585aa7795b"}, + {file = "exceptiongroup-1.2.2.tar.gz", hash = "sha256:47c2edf7c6738fafb49fd34290706d1a1a2f4d1c6df275526b62cbb4aa5393cc"}, +] + +[package.extras] +test = ["pytest (>=6)"] + [[package]] name = "expression" -version = "5.0.2" +version = "5.3.0" description = "Practical functional programming for Python 3.11+" optional = false -python-versions = ">=3.11,<4" +python-versions = "<4,>=3.10" files = [ - {file = "expression-5.0.2-py3-none-any.whl", hash = "sha256:2b54eeccb6247d86f598a3ce1a4e1efc56e4c7ca901f622d8203919d4106e147"}, - {file = "expression-5.0.2.tar.gz", hash = "sha256:37019851b0794820c1167b185d6be4a22111604f3bab221f4136e429e5d9b57f"}, + {file = "expression-5.3.0-py3-none-any.whl", hash = "sha256:951a07aa3e8676ca42af0f29ca2c4d01ea0742317fde981cba8cf49a0a118064"}, + {file = "expression-5.3.0.tar.gz", hash = "sha256:07a43669622851a413897b118319b4c9ac03e8251b6228683ebbf22f12827122"}, ] [package.dependencies] -typing-extensions = ">=4.1.1,<5.0.0" +typing-extensions = ">=4.6.0" [package.extras] -all = ["pydantic (>=2.0.0,<3.0.0)"] -pydantic = ["pydantic (>=2.0.0,<3.0.0)"] +all = ["pydantic (>=2.6.2,<3.0.0)"] +pydantic = ["pydantic (>=2.6.2,<3.0.0)"] [[package]] name = "filelock" -version = "3.13.1" +version = "3.16.1" description = "A platform independent file lock." optional = false python-versions = ">=3.8" files = [ - {file = "filelock-3.13.1-py3-none-any.whl", hash = "sha256:57dbda9b35157b05fb3e58ee91448612eb674172fab98ee235ccb0b5bee19a1c"}, - {file = "filelock-3.13.1.tar.gz", hash = "sha256:521f5f56c50f8426f5e03ad3b281b490a87ef15bc6c526f168290f0c7148d44e"}, + {file = "filelock-3.16.1-py3-none-any.whl", hash = "sha256:2082e5703d51fbf98ea75855d9d5527e33d8ff23099bec374a134febee6946b0"}, + {file = "filelock-3.16.1.tar.gz", hash = "sha256:c249fbfcd5db47e5e2d6d62198e565475ee65e4831e2561c8e313fa7eb961435"}, ] [package.extras] -docs = ["furo (>=2023.9.10)", "sphinx (>=7.2.6)", "sphinx-autodoc-typehints (>=1.24)"] -testing = ["covdefaults (>=2.3)", "coverage (>=7.3.2)", "diff-cover (>=8)", "pytest (>=7.4.3)", "pytest-cov (>=4.1)", "pytest-mock (>=3.12)", "pytest-timeout (>=2.2)"] -typing = ["typing-extensions (>=4.8)"] +docs = ["furo (>=2024.8.6)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4.1)"] +testing = ["covdefaults (>=2.3)", "coverage (>=7.6.1)", "diff-cover (>=9.2)", "pytest (>=8.3.3)", "pytest-asyncio (>=0.24)", "pytest-cov (>=5)", "pytest-mock (>=3.14)", "pytest-timeout (>=2.3.1)", "virtualenv (>=20.26.4)"] +typing = ["typing-extensions (>=4.12.2)"] [[package]] name = "identify" -version = "2.5.33" +version = "2.6.1" description = "File identification library for Python" optional = false python-versions = ">=3.8" files = [ - {file = "identify-2.5.33-py2.py3-none-any.whl", hash = "sha256:d40ce5fcd762817627670da8a7d8d8e65f24342d14539c59488dc603bf662e34"}, - {file = "identify-2.5.33.tar.gz", hash = "sha256:161558f9fe4559e1557e1bff323e8631f6a0e4837f7497767c1782832f16b62d"}, + {file = "identify-2.6.1-py2.py3-none-any.whl", hash = "sha256:53863bcac7caf8d2ed85bd20312ea5dcfc22226800f6d6881f232d861db5a8f0"}, + {file = "identify-2.6.1.tar.gz", hash = "sha256:91478c5fb7c3aac5ff7bf9b4344f803843dc586832d5f110d672b19aa1984c98"}, ] [package.extras] @@ -312,15 +312,18 @@ license = ["ukkonen"] [[package]] name = "idna" -version = "3.7" +version = "3.10" description = "Internationalized Domain Names in Applications (IDNA)" optional = false -python-versions = ">=3.5" +python-versions = ">=3.6" files = [ - {file = "idna-3.7-py3-none-any.whl", hash = "sha256:82fee1fc78add43492d3a1898bfa6d8a904cc97d8427f683ed8e798d07761aa0"}, - {file = "idna-3.7.tar.gz", hash = "sha256:028ff3aadf0609c1fd278d8ea3089299412a7a8b9bd005dd08b9f8285bcb5cfc"}, + {file = "idna-3.10-py3-none-any.whl", hash = "sha256:946d195a0d259cbba61165e88e65941f16e9b36ea6ddb97f00452bae8b1287d3"}, + {file = "idna-3.10.tar.gz", hash = "sha256:12f65c9b470abda6dc35cf8e63cc574b1c52b11df2c86030af0ac09b01b13ea9"}, ] +[package.extras] +all = ["flake8 (>=7.1.1)", "mypy (>=1.11.2)", "pytest (>=8.3.2)", "ruff (>=0.6.2)"] + [[package]] name = "iniconfig" version = "2.0.0" @@ -334,53 +337,51 @@ files = [ [[package]] name = "nodeenv" -version = "1.8.0" +version = "1.9.1" description = "Node.js virtual environment builder" optional = false -python-versions = ">=2.7,!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*" +python-versions = "!=3.0.*,!=3.1.*,!=3.2.*,!=3.3.*,!=3.4.*,!=3.5.*,!=3.6.*,>=2.7" files = [ - {file = "nodeenv-1.8.0-py2.py3-none-any.whl", hash = "sha256:df865724bb3c3adc86b3876fa209771517b0cfe596beff01a92700e0e8be4cec"}, - {file = "nodeenv-1.8.0.tar.gz", hash = "sha256:d51e0c37e64fbf47d017feac3145cdbb58836d7eee8c6f6d3b6880c5456227d2"}, + {file = "nodeenv-1.9.1-py2.py3-none-any.whl", hash = "sha256:ba11c9782d29c27c70ffbdda2d7415098754709be8a7056d79a737cd901155c9"}, + {file = "nodeenv-1.9.1.tar.gz", hash = "sha256:6ec12890a2dab7946721edbfbcd91f3319c6ccc9aec47be7c7e6b7011ee6645f"}, ] -[package.dependencies] -setuptools = "*" - [[package]] name = "packaging" -version = "23.2" +version = "24.1" description = "Core utilities for Python packages" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "packaging-23.2-py3-none-any.whl", hash = "sha256:8c491190033a9af7e1d931d0b5dacc2ef47509b34dd0de67ed209b5203fc88c7"}, - {file = "packaging-23.2.tar.gz", hash = "sha256:048fb0e9405036518eaaf48a55953c750c11e1a1b68e0dd1a9d62ed0c092cfc5"}, + {file = "packaging-24.1-py3-none-any.whl", hash = "sha256:5b8f2217dbdbd2f7f384c41c628544e6d52f2d0f53c6d0c3ea61aa5d1d7ff124"}, + {file = "packaging-24.1.tar.gz", hash = "sha256:026ed72c8ed3fcce5bf8950572258698927fd1dbda10a5e981cdf0ac37f4f002"}, ] [[package]] name = "platformdirs" -version = "4.1.0" -description = "A small Python package for determining appropriate platform-specific dirs, e.g. a \"user data dir\"." +version = "4.3.6" +description = "A small Python package for determining appropriate platform-specific dirs, e.g. a `user data dir`." optional = false python-versions = ">=3.8" files = [ - {file = "platformdirs-4.1.0-py3-none-any.whl", hash = "sha256:11c8f37bcca40db96d8144522d925583bdb7a31f7b0e37e3ed4318400a8e2380"}, - {file = "platformdirs-4.1.0.tar.gz", hash = "sha256:906d548203468492d432bcb294d4bc2fff751bf84971fbb2c10918cc206ee420"}, + {file = "platformdirs-4.3.6-py3-none-any.whl", hash = "sha256:73e575e1408ab8103900836b97580d5307456908a03e92031bab39e4554cc3fb"}, + {file = "platformdirs-4.3.6.tar.gz", hash = "sha256:357fb2acbc885b0419afd3ce3ed34564c13c9b95c89360cd9563f73aa5e2b907"}, ] [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.1)", "sphinx-autodoc-typehints (>=1.24)"] -test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=7.4)", "pytest-cov (>=4.1)", "pytest-mock (>=3.11.1)"] +docs = ["furo (>=2024.8.6)", "proselint (>=0.14)", "sphinx (>=8.0.2)", "sphinx-autodoc-typehints (>=2.4)"] +test = ["appdirs (==1.4.4)", "covdefaults (>=2.3)", "pytest (>=8.3.2)", "pytest-cov (>=5)", "pytest-mock (>=3.14)"] +type = ["mypy (>=1.11.2)"] [[package]] name = "pluggy" -version = "1.3.0" +version = "1.5.0" description = "plugin and hook calling mechanisms for python" optional = false python-versions = ">=3.8" files = [ - {file = "pluggy-1.3.0-py3-none-any.whl", hash = "sha256:d89c696a773f8bd377d18e5ecda92b7a3793cbe66c87060a6fb58c7b6e1061f7"}, - {file = "pluggy-1.3.0.tar.gz", hash = "sha256:cf61ae8f126ac6f7c451172cf30e3e43d3ca77615509771b3a984a0730651e12"}, + {file = "pluggy-1.5.0-py3-none-any.whl", hash = "sha256:44e1ad92c8ca002de6377e165f3e0f1be63266ab4d554740532335b9d75ea669"}, + {file = "pluggy-1.5.0.tar.gz", hash = "sha256:2cffa88e94fdc978c4c574f15f9e59b7f4201d439195c3715ca9e2486f1d0cf1"}, ] [package.extras] @@ -389,13 +390,13 @@ testing = ["pytest", "pytest-benchmark"] [[package]] name = "pre-commit" -version = "2.21.0" +version = "3.8.0" description = "A framework for managing and maintaining multi-language pre-commit hooks." optional = false -python-versions = ">=3.7" +python-versions = ">=3.9" files = [ - {file = "pre_commit-2.21.0-py2.py3-none-any.whl", hash = "sha256:e2f91727039fc39a92f58a588a25b87f936de6567eed4f0e673e0507edc75bad"}, - {file = "pre_commit-2.21.0.tar.gz", hash = "sha256:31ef31af7e474a8d8995027fefdfcf509b5c913ff31f2015b4ec4beb26a6f658"}, + {file = "pre_commit-3.8.0-py2.py3-none-any.whl", hash = "sha256:9a90a53bf82fdd8778d58085faf8d83df56e40dfe18f45b19446e26bf1b3a63f"}, + {file = "pre_commit-3.8.0.tar.gz", hash = "sha256:8bb6494d4a20423842e198980c9ecf9f96607a07ea29549e180eef9ae80fe7af"}, ] [package.dependencies] @@ -405,113 +406,106 @@ nodeenv = ">=0.11.1" pyyaml = ">=5.1" virtualenv = ">=20.10.0" -[[package]] -name = "pyflakes" -version = "2.5.0" -description = "passive checker of Python programs" -optional = false -python-versions = ">=3.6" -files = [ - {file = "pyflakes-2.5.0-py2.py3-none-any.whl", hash = "sha256:4579f67d887f804e67edb544428f264b7b24f435b263c4614f384135cea553d2"}, - {file = "pyflakes-2.5.0.tar.gz", hash = "sha256:491feb020dca48ccc562a8c0cbe8df07ee13078df59813b83959cbdada312ea3"}, -] - [[package]] name = "pytest" -version = "7.4.4" +version = "8.3.3" description = "pytest: simple powerful testing with Python" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-7.4.4-py3-none-any.whl", hash = "sha256:b090cdf5ed60bf4c45261be03239c2c1c22df034fbffe691abe93cd80cea01d8"}, - {file = "pytest-7.4.4.tar.gz", hash = "sha256:2cf0005922c6ace4a3e2ec8b4080eb0d9753fdc93107415332f50ce9e7994280"}, + {file = "pytest-8.3.3-py3-none-any.whl", hash = "sha256:a6853c7375b2663155079443d2e45de913a911a11d669df02a50814944db57b2"}, + {file = "pytest-8.3.3.tar.gz", hash = "sha256:70b98107bd648308a7952b06e6ca9a50bc660be218d53c257cc1fc94fda10181"}, ] [package.dependencies] colorama = {version = "*", markers = "sys_platform == \"win32\""} +exceptiongroup = {version = ">=1.0.0rc8", markers = "python_version < \"3.11\""} iniconfig = "*" packaging = "*" -pluggy = ">=0.12,<2.0" +pluggy = ">=1.5,<2" +tomli = {version = ">=1", markers = "python_version < \"3.11\""} [package.extras] -testing = ["argcomplete", "attrs (>=19.2.0)", "hypothesis (>=3.56)", "mock", "nose", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] +dev = ["argcomplete", "attrs (>=19.2)", "hypothesis (>=3.56)", "mock", "pygments (>=2.7.2)", "requests", "setuptools", "xmlschema"] [[package]] name = "pytest-asyncio" -version = "0.18.3" +version = "0.24.0" description = "Pytest support for asyncio" optional = false -python-versions = ">=3.7" +python-versions = ">=3.8" files = [ - {file = "pytest-asyncio-0.18.3.tar.gz", hash = "sha256:7659bdb0a9eb9c6e3ef992eef11a2b3e69697800ad02fb06374a210d85b29f91"}, - {file = "pytest_asyncio-0.18.3-1-py3-none-any.whl", hash = "sha256:16cf40bdf2b4fb7fc8e4b82bd05ce3fbcd454cbf7b92afc445fe299dabb88213"}, - {file = "pytest_asyncio-0.18.3-py3-none-any.whl", hash = "sha256:8fafa6c52161addfd41ee7ab35f11836c5a16ec208f93ee388f752bea3493a84"}, + {file = "pytest_asyncio-0.24.0-py3-none-any.whl", hash = "sha256:a811296ed596b69bf0b6f3dc40f83bcaf341b155a269052d82efa2b25ac7037b"}, + {file = "pytest_asyncio-0.24.0.tar.gz", hash = "sha256:d081d828e576d85f875399194281e92bf8a68d60d72d1a2faf2feddb6c46b276"}, ] [package.dependencies] -pytest = ">=6.1.0" +pytest = ">=8.2,<9" [package.extras] -testing = ["coverage (==6.2)", "flaky (>=3.5.0)", "hypothesis (>=5.7.1)", "mypy (==0.931)", "pytest-trio (>=0.7.0)"] +docs = ["sphinx (>=5.3)", "sphinx-rtd-theme (>=1.0)"] +testing = ["coverage (>=6.2)", "hypothesis (>=5.7.1)"] [[package]] name = "pyyaml" -version = "6.0.1" +version = "6.0.2" description = "YAML parser and emitter for Python" optional = false -python-versions = ">=3.6" +python-versions = ">=3.8" files = [ - {file = "PyYAML-6.0.1-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:d858aa552c999bc8a8d57426ed01e40bef403cd8ccdd0fc5f6f04a00414cac2a"}, - {file = "PyYAML-6.0.1-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:fd66fc5d0da6d9815ba2cebeb4205f95818ff4b79c3ebe268e75d961704af52f"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:69b023b2b4daa7548bcfbd4aa3da05b3a74b772db9e23b982788168117739938"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:81e0b275a9ecc9c0c0c07b4b90ba548307583c125f54d5b6946cfee6360c733d"}, - {file = "PyYAML-6.0.1-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ba336e390cd8e4d1739f42dfe9bb83a3cc2e80f567d8805e11b46f4a943f5515"}, - {file = "PyYAML-6.0.1-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:326c013efe8048858a6d312ddd31d56e468118ad4cdeda36c719bf5bb6192290"}, - {file = "PyYAML-6.0.1-cp310-cp310-win32.whl", hash = "sha256:bd4af7373a854424dabd882decdc5579653d7868b8fb26dc7d0e99f823aa5924"}, - {file = "PyYAML-6.0.1-cp310-cp310-win_amd64.whl", hash = "sha256:fd1592b3fdf65fff2ad0004b5e363300ef59ced41c2e6b3a99d4089fa8c5435d"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:6965a7bc3cf88e5a1c3bd2e0b5c22f8d677dc88a455344035f03399034eb3007"}, - {file = "PyYAML-6.0.1-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:f003ed9ad21d6a4713f0a9b5a7a0a79e08dd0f221aff4525a2be4c346ee60aab"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:42f8152b8dbc4fe7d96729ec2b99c7097d656dc1213a3229ca5383f973a5ed6d"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:062582fca9fabdd2c8b54a3ef1c978d786e0f6b3a1510e0ac93ef59e0ddae2bc"}, - {file = "PyYAML-6.0.1-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:d2b04aac4d386b172d5b9692e2d2da8de7bfb6c387fa4f801fbf6fb2e6ba4673"}, - {file = "PyYAML-6.0.1-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:e7d73685e87afe9f3b36c799222440d6cf362062f78be1013661b00c5c6f678b"}, - {file = "PyYAML-6.0.1-cp311-cp311-win32.whl", hash = "sha256:1635fd110e8d85d55237ab316b5b011de701ea0f29d07611174a1b42f1444741"}, - {file = "PyYAML-6.0.1-cp311-cp311-win_amd64.whl", hash = "sha256:bf07ee2fef7014951eeb99f56f39c9bb4af143d8aa3c21b1677805985307da34"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:855fb52b0dc35af121542a76b9a84f8d1cd886ea97c84703eaa6d88e37a2ad28"}, - {file = "PyYAML-6.0.1-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:40df9b996c2b73138957fe23a16a4f0ba614f4c0efce1e9406a184b6d07fa3a9"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a08c6f0fe150303c1c6b71ebcd7213c2858041a7e01975da3a99aed1e7a378ef"}, - {file = "PyYAML-6.0.1-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:6c22bec3fbe2524cde73d7ada88f6566758a8f7227bfbf93a408a9d86bcc12a0"}, - {file = "PyYAML-6.0.1-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8d4e9c88387b0f5c7d5f281e55304de64cf7f9c0021a3525bd3b1c542da3b0e4"}, - {file = "PyYAML-6.0.1-cp312-cp312-win32.whl", hash = "sha256:d483d2cdf104e7c9fa60c544d92981f12ad66a457afae824d146093b8c294c54"}, - {file = "PyYAML-6.0.1-cp312-cp312-win_amd64.whl", hash = "sha256:0d3304d8c0adc42be59c5f8a4d9e3d7379e6955ad754aa9d6ab7a398b59dd1df"}, - {file = "PyYAML-6.0.1-cp36-cp36m-macosx_10_9_x86_64.whl", hash = "sha256:50550eb667afee136e9a77d6dc71ae76a44df8b3e51e41b77f6de2932bfe0f47"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1fe35611261b29bd1de0070f0b2f47cb6ff71fa6595c077e42bd0c419fa27b98"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:704219a11b772aea0d8ecd7058d0082713c3562b4e271b849ad7dc4a5c90c13c"}, - {file = "PyYAML-6.0.1-cp36-cp36m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:afd7e57eddb1a54f0f1a974bc4391af8bcce0b444685d936840f125cf046d5bd"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win32.whl", hash = "sha256:fca0e3a251908a499833aa292323f32437106001d436eca0e6e7833256674585"}, - {file = "PyYAML-6.0.1-cp36-cp36m-win_amd64.whl", hash = "sha256:f22ac1c3cac4dbc50079e965eba2c1058622631e526bd9afd45fedd49ba781fa"}, - {file = "PyYAML-6.0.1-cp37-cp37m-macosx_10_9_x86_64.whl", hash = "sha256:b1275ad35a5d18c62a7220633c913e1b42d44b46ee12554e5fd39c70a243d6a3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:18aeb1bf9a78867dc38b259769503436b7c72f7a1f1f4c93ff9a17de54319b27"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:596106435fa6ad000c2991a98fa58eeb8656ef2325d7e158344fb33864ed87e3"}, - {file = "PyYAML-6.0.1-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:baa90d3f661d43131ca170712d903e6295d1f7a0f595074f151c0aed377c9b9c"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win32.whl", hash = "sha256:9046c58c4395dff28dd494285c82ba00b546adfc7ef001486fbf0324bc174fba"}, - {file = "PyYAML-6.0.1-cp37-cp37m-win_amd64.whl", hash = "sha256:4fb147e7a67ef577a588a0e2c17b6db51dda102c71de36f8549b6816a96e1867"}, - {file = "PyYAML-6.0.1-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:1d4c7e777c441b20e32f52bd377e0c409713e8bb1386e1099c2415f26e479595"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:a0cd17c15d3bb3fa06978b4e8958dcdc6e0174ccea823003a106c7d4d7899ac5"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:28c119d996beec18c05208a8bd78cbe4007878c6dd15091efb73a30e90539696"}, - {file = "PyYAML-6.0.1-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:7e07cbde391ba96ab58e532ff4803f79c4129397514e1413a7dc761ccd755735"}, - {file = "PyYAML-6.0.1-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:49a183be227561de579b4a36efbb21b3eab9651dd81b1858589f796549873dd6"}, - {file = "PyYAML-6.0.1-cp38-cp38-win32.whl", hash = "sha256:184c5108a2aca3c5b3d3bf9395d50893a7ab82a38004c8f61c258d4428e80206"}, - {file = "PyYAML-6.0.1-cp38-cp38-win_amd64.whl", hash = "sha256:1e2722cc9fbb45d9b87631ac70924c11d3a401b2d7f410cc0e3bbf249f2dca62"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:9eb6caa9a297fc2c2fb8862bc5370d0303ddba53ba97e71f08023b6cd73d16a8"}, - {file = "PyYAML-6.0.1-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:c8098ddcc2a85b61647b2590f825f3db38891662cfc2fc776415143f599bb859"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5773183b6446b2c99bb77e77595dd486303b4faab2b086e7b17bc6bef28865f6"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:b786eecbdf8499b9ca1d697215862083bd6d2a99965554781d0d8d1ad31e13a0"}, - {file = "PyYAML-6.0.1-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:bc1bf2925a1ecd43da378f4db9e4f799775d6367bdb94671027b73b393a7c42c"}, - {file = "PyYAML-6.0.1-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:04ac92ad1925b2cff1db0cfebffb6ffc43457495c9b3c39d3fcae417d7125dc5"}, - {file = "PyYAML-6.0.1-cp39-cp39-win32.whl", hash = "sha256:faca3bdcf85b2fc05d06ff3fbc1f83e1391b3e724afa3feba7d13eeab355484c"}, - {file = "PyYAML-6.0.1-cp39-cp39-win_amd64.whl", hash = "sha256:510c9deebc5c0225e8c96813043e62b680ba2f9c50a08d3724c7f28a747d1486"}, - {file = "PyYAML-6.0.1.tar.gz", hash = "sha256:bfdf460b1736c775f2ba9f6a92bca30bc2095067b8a9d77876d1fad6cc3b4a43"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_10_9_x86_64.whl", hash = "sha256:0a9a2848a5b7feac301353437eb7d5957887edbf81d56e903999a75a3d743086"}, + {file = "PyYAML-6.0.2-cp310-cp310-macosx_11_0_arm64.whl", hash = "sha256:29717114e51c84ddfba879543fb232a6ed60086602313ca38cce623c1d62cfbf"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:8824b5a04a04a047e72eea5cec3bc266db09e35de6bdfe34c9436ac5ee27d237"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:7c36280e6fb8385e520936c3cb3b8042851904eba0e58d277dca80a5cfed590b"}, + {file = "PyYAML-6.0.2-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:ec031d5d2feb36d1d1a24380e4db6d43695f3748343d99434e6f5f9156aaa2ed"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_aarch64.whl", hash = "sha256:936d68689298c36b53b29f23c6dbb74de12b4ac12ca6cfe0e047bedceea56180"}, + {file = "PyYAML-6.0.2-cp310-cp310-musllinux_1_1_x86_64.whl", hash = "sha256:23502f431948090f597378482b4812b0caae32c22213aecf3b55325e049a6c68"}, + {file = "PyYAML-6.0.2-cp310-cp310-win32.whl", hash = "sha256:2e99c6826ffa974fe6e27cdb5ed0021786b03fc98e5ee3c5bfe1fd5015f42b99"}, + {file = "PyYAML-6.0.2-cp310-cp310-win_amd64.whl", hash = "sha256:a4d3091415f010369ae4ed1fc6b79def9416358877534caf6a0fdd2146c87a3e"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_10_9_x86_64.whl", hash = "sha256:cc1c1159b3d456576af7a3e4d1ba7e6924cb39de8f67111c735f6fc832082774"}, + {file = "PyYAML-6.0.2-cp311-cp311-macosx_11_0_arm64.whl", hash = "sha256:1e2120ef853f59c7419231f3bf4e7021f1b936f6ebd222406c3b60212205d2ee"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:5d225db5a45f21e78dd9358e58a98702a0302f2659a3c6cd320564b75b86f47c"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:5ac9328ec4831237bec75defaf839f7d4564be1e6b25ac710bd1a96321cc8317"}, + {file = "PyYAML-6.0.2-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3ad2a3decf9aaba3d29c8f537ac4b243e36bef957511b4766cb0057d32b0be85"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_aarch64.whl", hash = "sha256:ff3824dc5261f50c9b0dfb3be22b4567a6f938ccce4587b38952d85fd9e9afe4"}, + {file = "PyYAML-6.0.2-cp311-cp311-musllinux_1_1_x86_64.whl", hash = "sha256:797b4f722ffa07cc8d62053e4cff1486fa6dc094105d13fea7b1de7d8bf71c9e"}, + {file = "PyYAML-6.0.2-cp311-cp311-win32.whl", hash = "sha256:11d8f3dd2b9c1207dcaf2ee0bbbfd5991f571186ec9cc78427ba5bd32afae4b5"}, + {file = "PyYAML-6.0.2-cp311-cp311-win_amd64.whl", hash = "sha256:e10ce637b18caea04431ce14fabcf5c64a1c61ec9c56b071a4b7ca131ca52d44"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_10_9_x86_64.whl", hash = "sha256:c70c95198c015b85feafc136515252a261a84561b7b1d51e3384e0655ddf25ab"}, + {file = "PyYAML-6.0.2-cp312-cp312-macosx_11_0_arm64.whl", hash = "sha256:ce826d6ef20b1bc864f0a68340c8b3287705cae2f8b4b1d932177dcc76721725"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:1f71ea527786de97d1a0cc0eacd1defc0985dcf6b3f17bb77dcfc8c34bec4dc5"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:9b22676e8097e9e22e36d6b7bda33190d0d400f345f23d4065d48f4ca7ae0425"}, + {file = "PyYAML-6.0.2-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:80bab7bfc629882493af4aa31a4cfa43a4c57c83813253626916b8c7ada83476"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_aarch64.whl", hash = "sha256:0833f8694549e586547b576dcfaba4a6b55b9e96098b36cdc7ebefe667dfed48"}, + {file = "PyYAML-6.0.2-cp312-cp312-musllinux_1_1_x86_64.whl", hash = "sha256:8b9c7197f7cb2738065c481a0461e50ad02f18c78cd75775628afb4d7137fb3b"}, + {file = "PyYAML-6.0.2-cp312-cp312-win32.whl", hash = "sha256:ef6107725bd54b262d6dedcc2af448a266975032bc85ef0172c5f059da6325b4"}, + {file = "PyYAML-6.0.2-cp312-cp312-win_amd64.whl", hash = "sha256:7e7401d0de89a9a855c839bc697c079a4af81cf878373abd7dc625847d25cbd8"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_10_13_x86_64.whl", hash = "sha256:efdca5630322a10774e8e98e1af481aad470dd62c3170801852d752aa7a783ba"}, + {file = "PyYAML-6.0.2-cp313-cp313-macosx_11_0_arm64.whl", hash = "sha256:50187695423ffe49e2deacb8cd10510bc361faac997de9efef88badc3bb9e2d1"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:0ffe8360bab4910ef1b9e87fb812d8bc0a308b0d0eef8c8f44e0254ab3b07133"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:17e311b6c678207928d649faa7cb0d7b4c26a0ba73d41e99c4fff6b6c3276484"}, + {file = "PyYAML-6.0.2-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:70b189594dbe54f75ab3a1acec5f1e3faa7e8cf2f1e08d9b561cb41b845f69d5"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_aarch64.whl", hash = "sha256:41e4e3953a79407c794916fa277a82531dd93aad34e29c2a514c2c0c5fe971cc"}, + {file = "PyYAML-6.0.2-cp313-cp313-musllinux_1_1_x86_64.whl", hash = "sha256:68ccc6023a3400877818152ad9a1033e3db8625d899c72eacb5a668902e4d652"}, + {file = "PyYAML-6.0.2-cp313-cp313-win32.whl", hash = "sha256:bc2fa7c6b47d6bc618dd7fb02ef6fdedb1090ec036abab80d4681424b84c1183"}, + {file = "PyYAML-6.0.2-cp313-cp313-win_amd64.whl", hash = "sha256:8388ee1976c416731879ac16da0aff3f63b286ffdd57cdeb95f3f2e085687563"}, + {file = "PyYAML-6.0.2-cp38-cp38-macosx_10_9_x86_64.whl", hash = "sha256:24471b829b3bf607e04e88d79542a9d48bb037c2267d7927a874e6c205ca7e9a"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d7fded462629cfa4b685c5416b949ebad6cec74af5e2d42905d41e257e0869f5"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:d84a1718ee396f54f3a086ea0a66d8e552b2ab2017ef8b420e92edbc841c352d"}, + {file = "PyYAML-6.0.2-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:9056c1ecd25795207ad294bcf39f2db3d845767be0ea6e6a34d856f006006083"}, + {file = "PyYAML-6.0.2-cp38-cp38-musllinux_1_1_x86_64.whl", hash = "sha256:82d09873e40955485746739bcb8b4586983670466c23382c19cffecbf1fd8706"}, + {file = "PyYAML-6.0.2-cp38-cp38-win32.whl", hash = "sha256:43fa96a3ca0d6b1812e01ced1044a003533c47f6ee8aca31724f78e93ccc089a"}, + {file = "PyYAML-6.0.2-cp38-cp38-win_amd64.whl", hash = "sha256:01179a4a8559ab5de078078f37e5c1a30d76bb88519906844fd7bdea1b7729ff"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_10_9_x86_64.whl", hash = "sha256:688ba32a1cffef67fd2e9398a2efebaea461578b0923624778664cc1c914db5d"}, + {file = "PyYAML-6.0.2-cp39-cp39-macosx_11_0_arm64.whl", hash = "sha256:a8786accb172bd8afb8be14490a16625cbc387036876ab6ba70912730faf8e1f"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_aarch64.manylinux2014_aarch64.whl", hash = "sha256:d8e03406cac8513435335dbab54c0d385e4a49e4945d2909a581c83647ca0290"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_s390x.manylinux2014_s390x.whl", hash = "sha256:f753120cb8181e736c57ef7636e83f31b9c0d1722c516f7e86cf15b7aa57ff12"}, + {file = "PyYAML-6.0.2-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl", hash = "sha256:3b1fdb9dc17f5a7677423d508ab4f243a726dea51fa5e70992e59a7411c89d19"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_aarch64.whl", hash = "sha256:0b69e4ce7a131fe56b7e4d770c67429700908fc0752af059838b1cfb41960e4e"}, + {file = "PyYAML-6.0.2-cp39-cp39-musllinux_1_1_x86_64.whl", hash = "sha256:a9f8c2e67970f13b16084e04f134610fd1d374bf477b17ec1599185cf611d725"}, + {file = "PyYAML-6.0.2-cp39-cp39-win32.whl", hash = "sha256:6395c297d42274772abc367baaa79683958044e5d3835486c16da75d2a694631"}, + {file = "PyYAML-6.0.2-cp39-cp39-win_amd64.whl", hash = "sha256:39693e1f8320ae4f43943590b49779ffb98acb81f788220ea932a6b6c51004d8"}, + {file = "pyyaml-6.0.2.tar.gz", hash = "sha256:d584d9ec91ad65861cc08d42e834324ef890a082e591037abe114850ff7bbc3e"}, ] [[package]] @@ -530,13 +524,13 @@ typing-extensions = ">=4.1.1,<5.0.0" [[package]] name = "requests" -version = "2.32.0" +version = "2.32.3" description = "Python HTTP for Humans." optional = false python-versions = ">=3.8" files = [ - {file = "requests-2.32.0-py3-none-any.whl", hash = "sha256:f2c3881dddb70d056c5bd7600a4fae312b2a300e39be6a118d30b90bd27262b5"}, - {file = "requests-2.32.0.tar.gz", hash = "sha256:fa5490319474c82ef1d2c9bc459d3652e3ae4ef4c4ebdd18a21145a47ca4b6b8"}, + {file = "requests-2.32.3-py3-none-any.whl", hash = "sha256:70761cfe03c773ceb22aa2f671b4757976145175cdfca038c02654d061d6dcc6"}, + {file = "requests-2.32.3.tar.gz", hash = "sha256:55365417734eb18255590a9ff9eb97e9e1da868d4ccd6402399eaf68af20a760"}, ] [package.dependencies] @@ -550,57 +544,53 @@ socks = ["PySocks (>=1.5.6,!=1.5.7)"] use-chardet-on-py3 = ["chardet (>=3.0.2,<6)"] [[package]] -name = "setuptools" -version = "69.0.3" -description = "Easily download, build, install, upgrade, and uninstall Python packages" +name = "tomli" +version = "2.0.1" +description = "A lil' TOML parser" optional = false -python-versions = ">=3.8" +python-versions = ">=3.7" files = [ - {file = "setuptools-69.0.3-py3-none-any.whl", hash = "sha256:385eb4edd9c9d5c17540511303e39a147ce2fc04bc55289c322b9e5904fe2c05"}, - {file = "setuptools-69.0.3.tar.gz", hash = "sha256:be1af57fc409f93647f2e8e4573a142ed38724b8cdd389706a867bb4efcf1e78"}, + {file = "tomli-2.0.1-py3-none-any.whl", hash = "sha256:939de3e7a6161af0c887ef91b7d41a53e7c5a1ca976325f429cb46ea9bc30ecc"}, + {file = "tomli-2.0.1.tar.gz", hash = "sha256:de526c12914f0c550d15924c62d72abc48d6fe7364aa87328337a31007fe8a4f"}, ] -[package.extras] -docs = ["furo", "jaraco.packaging (>=9.3)", "jaraco.tidelift (>=1.4)", "pygments-github-lexers (==0.0.5)", "rst.linker (>=1.9)", "sphinx (<7.2.5)", "sphinx (>=3.5)", "sphinx-favicon", "sphinx-inline-tabs", "sphinx-lint", "sphinx-notfound-page (>=1,<2)", "sphinx-reredirects", "sphinxcontrib-towncrier"] -testing = ["build[virtualenv]", "filelock (>=3.4.0)", "flake8-2020", "ini2toml[lite] (>=0.9)", "jaraco.develop (>=7.21)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "pip (>=19.1)", "pytest (>=6)", "pytest-black (>=0.3.7)", "pytest-checkdocs (>=2.4)", "pytest-cov", "pytest-enabler (>=2.2)", "pytest-mypy (>=0.9.1)", "pytest-perf", "pytest-ruff", "pytest-timeout", "pytest-xdist", "tomli-w (>=1.0.0)", "virtualenv (>=13.0.0)", "wheel"] -testing-integration = ["build[virtualenv] (>=1.0.3)", "filelock (>=3.4.0)", "jaraco.envs (>=2.2)", "jaraco.path (>=3.2.0)", "packaging (>=23.1)", "pytest", "pytest-enabler", "pytest-xdist", "tomli", "virtualenv (>=13.0.0)", "wheel"] - [[package]] name = "typing-extensions" -version = "4.9.0" +version = "4.12.2" description = "Backported and Experimental Type Hints for Python 3.8+" optional = false python-versions = ">=3.8" files = [ - {file = "typing_extensions-4.9.0-py3-none-any.whl", hash = "sha256:af72aea155e91adfc61c3ae9e0e342dbc0cba726d6cba4b6c72c1f34e47291cd"}, - {file = "typing_extensions-4.9.0.tar.gz", hash = "sha256:23478f88c37f27d76ac8aee6c905017a143b0b1b886c3c9f66bc2fd94f9f5783"}, + {file = "typing_extensions-4.12.2-py3-none-any.whl", hash = "sha256:04e5ca0351e0f3f85c6853954072df659d0d13fac324d0072316b67d7794700d"}, + {file = "typing_extensions-4.12.2.tar.gz", hash = "sha256:1a7ead55c7e559dd4dee8856e3a88b41225abfe1ce8df57b7c13915fe121ffb8"}, ] [[package]] name = "urllib3" -version = "2.1.0" +version = "2.2.3" description = "HTTP library with thread-safe connection pooling, file post, and more." optional = false python-versions = ">=3.8" files = [ - {file = "urllib3-2.1.0-py3-none-any.whl", hash = "sha256:55901e917a5896a349ff771be919f8bd99aff50b79fe58fec595eb37bbc56bb3"}, - {file = "urllib3-2.1.0.tar.gz", hash = "sha256:df7aa8afb0148fa78488e7899b2c59b5f4ffcfa82e6c54ccb9dd37c1d7b52d54"}, + {file = "urllib3-2.2.3-py3-none-any.whl", hash = "sha256:ca899ca043dcb1bafa3e262d73aa25c465bfb49e0bd9dd5d59f1d0acba2f8fac"}, + {file = "urllib3-2.2.3.tar.gz", hash = "sha256:e7d814a81dad81e6caf2ec9fdedb284ecc9c73076b62654547cc64ccdcae26e9"}, ] [package.extras] brotli = ["brotli (>=1.0.9)", "brotlicffi (>=0.8.0)"] +h2 = ["h2 (>=4,<5)"] socks = ["pysocks (>=1.5.6,!=1.5.7,<2.0)"] zstd = ["zstandard (>=0.18.0)"] [[package]] name = "virtualenv" -version = "20.25.0" +version = "20.26.6" description = "Virtual Python Environment builder" optional = false python-versions = ">=3.7" files = [ - {file = "virtualenv-20.25.0-py3-none-any.whl", hash = "sha256:4238949c5ffe6876362d9c0180fc6c3a824a7b12b80604eeb8085f2ed7460de3"}, - {file = "virtualenv-20.25.0.tar.gz", hash = "sha256:bf51c0d9c7dd63ea8e44086fa1e4fb1093a31e963b86959257378aef020e1f1b"}, + {file = "virtualenv-20.26.6-py3-none-any.whl", hash = "sha256:7345cc5b25405607a624d8418154577459c3e0277f5466dd79c49d5e492995f2"}, + {file = "virtualenv-20.26.6.tar.gz", hash = "sha256:280aede09a2a5c317e409a00102e7077c6432c5a38f0ef938e643805a7ad2c48"}, ] [package.dependencies] @@ -609,10 +599,10 @@ filelock = ">=3.12.2,<4" platformdirs = ">=3.9.1,<5" [package.extras] -docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] +docs = ["furo (>=2023.7.26)", "proselint (>=0.13)", "sphinx (>=7.1.2,!=7.3)", "sphinx-argparse (>=0.4)", "sphinxcontrib-towncrier (>=0.2.1a0)", "towncrier (>=23.6)"] test = ["covdefaults (>=2.3)", "coverage (>=7.2.7)", "coverage-enable-subprocess (>=1)", "flaky (>=3.7)", "packaging (>=23.1)", "pytest (>=7.4)", "pytest-env (>=0.8.2)", "pytest-freezer (>=0.4.8)", "pytest-mock (>=3.11.1)", "pytest-randomly (>=3.12)", "pytest-timeout (>=2.1)", "setuptools (>=68)", "time-machine (>=2.10)"] [metadata] lock-version = "2.0" -python-versions = ">= 3.11, < 4" -content-hash = "f58815388ad47a96fe03eb2d6a1fc23f057dd008ec0bade544bee51ac50ce224" +python-versions = ">= 3.10, < 4" +content-hash = "6b75728d3702ddf8dfcad0ffa98fcdb06335154840edc8c296168dce60091641" diff --git a/pyproject.toml b/pyproject.toml index 15324b5..5a0418f 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,7 +1,7 @@ [tool.poetry] name = "aioreactive" version = "0.0.0" # NOTE: will be updated by publish script -description = "sync/await Reactive Tools for Python 3.11+" +description = "sync/await Reactive Tools for Python 3.10+" readme = "README.md" authors = ["Dag Brattli ", "Børge Lanes"] license = "MIT License" @@ -20,18 +20,17 @@ classifiers = [ packages = [{ include = "aioreactive" }, { include = "aioreactive/py.typed" }] [tool.poetry.dependencies] -python = ">= 3.11, < 4" +python = ">= 3.10, < 4" typing-extensions = "^4.1.1" -Expression = "^5.0.1" +Expression = "^5.3.0" reactivex = "^4.0.0" [tool.poetry.dev-dependencies] -pytest-asyncio = "^0.18.1" -pytest = "^7.4.4" +pytest-asyncio = "^0.24.0" +pytest = "^8.3.3" coverage = "^6.3.2" coveralls = "^3.3.1" -pre-commit = "^2.17.0" -autoflake = "^1.4" +pre-commit = "^3.8.0" dunamai = "^1.9.0" [tool.ruff] diff --git a/pyrightconfig.json b/pyrightconfig.json index 8a07b5b..931df36 100644 --- a/pyrightconfig.json +++ b/pyrightconfig.json @@ -7,6 +7,6 @@ ], "reportImportCycles": false, "reportMissingImports": false, - "pythonVersion": "3.11", + "pythonVersion": "3.10", "typeCheckingMode": "strict" } \ No newline at end of file diff --git a/tests/test_async_iteration.py b/tests/test_async_iteration.py index b351d95..712756f 100644 --- a/tests/test_async_iteration.py +++ b/tests/test_async_iteration.py @@ -9,14 +9,14 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type: ignore +@pytest.fixture(scope="function") # type: ignore def event_loop(): loop = VirtualTimeEventLoop() yield loop loop.close() -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_async_iteration() -> None: xs = rx.from_iterable([1, 2, 3]) result: list[int] = [] @@ -27,7 +27,7 @@ async def test_async_iteration() -> None: assert result == [1, 2, 3] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_async_comprehension() -> None: xs = rx.from_iterable([1, 2, 3]) @@ -36,7 +36,7 @@ async def test_async_comprehension() -> None: assert result == [1, 2, 3] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_async_iteration_aync_with() -> None: xs = rx.from_iterable([1, 2, 3]) result: list[int] = [] @@ -48,7 +48,7 @@ async def test_async_iteration_aync_with() -> None: assert result == [1, 2, 3] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_async_iteration_inception() -> None: # iterable to async source to async iterator to async source xs = rx.from_iterable([1, 2, 3]) diff --git a/tests/test_chain.py b/tests/test_chain.py index 1451cf5..86e5edb 100644 --- a/tests/test_chain.py +++ b/tests/test_chain.py @@ -11,14 +11,17 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + + +@pytest.mark.asyncio(loop_scope="module") async def test_chain_map(): xs = AsyncRx.from_iterable([1, 2, 3]) @@ -38,7 +41,7 @@ def mapper(value: int) -> int: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_chain_simple_pipe(): xs = AsyncRx.from_iterable([1, 2, 3]) @@ -62,7 +65,7 @@ async def predicate(value: int) -> bool: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_chain_complex_pipe(): xs = AsyncRx.from_iterable([1, 2, 3]) diff --git a/tests/test_debounce.py b/tests/test_debounce.py index b75a51b..af4b85a 100644 --- a/tests/test_debounce.py +++ b/tests/test_debounce.py @@ -17,14 +17,17 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + + +@pytest.mark.asyncio(loop_scope="module") async def test_debounce(): xs: AsyncTestSubject[int] = AsyncTestSubject() @@ -50,7 +53,7 @@ async def test_debounce(): await subscription.dispose_async() -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_debounce_filter(): xs: AsyncTestSubject[int] = AsyncTestSubject() diff --git a/tests/test_delay.py b/tests/test_delay.py index 63ab45d..6b23edb 100644 --- a/tests/test_delay.py +++ b/tests/test_delay.py @@ -17,14 +17,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_delay_done(): xs: AsyncTestSubject[int] = AsyncTestSubject() @@ -43,7 +45,7 @@ async def test_delay_done(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_delay_cancel_before_done(): xs: AsyncTestSubject[int] = AsyncTestSubject() @@ -60,7 +62,7 @@ async def test_delay_cancel_before_done(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_delay_throw(): error = Exception("ex") xs: AsyncTestSubject[int] = AsyncTestSubject() diff --git a/tests/test_distinct_until_changed.py b/tests/test_distinct_until_changed.py index 85eaa86..240ff2e 100644 --- a/tests/test_distinct_until_changed.py +++ b/tests/test_distinct_until_changed.py @@ -1,3 +1,4 @@ +import asyncio import pytest from expression.core import pipe @@ -11,14 +12,16 @@ class MyException(Exception): pass -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_distinct_until_changed_different(): xs = rx.from_iterable([1, 2, 3]) @@ -34,7 +37,7 @@ async def test_distinct_until_changed_different(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_distinct_until_changed_changed(): xs = AsyncRx.from_iterable([1, 2, 2, 1, 3, 3, 1, 2, 2]) diff --git a/tests/test_eventloop.py b/tests/test_eventloop.py index f4796be..5f4317a 100644 --- a/tests/test_eventloop.py +++ b/tests/test_eventloop.py @@ -6,14 +6,16 @@ from aioreactive.testing import VirtualTimeEventLoop -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_sleep(): loop = asyncio.get_event_loop() await asyncio.sleep(100) @@ -22,7 +24,7 @@ async def test_sleep(): assert loop.time() == 200 -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_call_soon(): result = [] @@ -37,7 +39,7 @@ def action(value: int) -> None: assert result == [1, 2, 3] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_call_later(): result = [] @@ -52,7 +54,7 @@ def action(value: int) -> None: assert result == [2, 3, 1] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_call_at(): result = [] @@ -67,7 +69,7 @@ def action(value: int) -> None: assert result == [2, 3, 1] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_cancel(): result = [] diff --git a/tests/test_filter.py b/tests/test_filter.py index 0ec4945..83779e0 100644 --- a/tests/test_filter.py +++ b/tests/test_filter.py @@ -12,14 +12,16 @@ class MyException(Exception): pass -@pytest.fixture() # type:ignore -def event_loop() -> Generator[Any, Any, Any]: - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_filter_happy() -> None: xs = rx.from_iterable([1, 2, 3]) result = [] @@ -37,7 +39,7 @@ async def predicate(value: int) -> bool: assert result == [2, 3] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_filter_predicate_throws() -> None: xs = rx.from_iterable([1, 2, 3]) err = MyException("err") diff --git a/tests/test_flat_map.py b/tests/test_flat_map.py index 1251bef..ceaedab 100644 --- a/tests/test_flat_map.py +++ b/tests/test_flat_map.py @@ -1,3 +1,4 @@ +import asyncio import pytest from expression.core import pipe @@ -7,14 +8,16 @@ from aioreactive.types import AsyncObservable -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_flap_map_done(): xs: rx.AsyncSubject[int] = rx.AsyncSubject() @@ -34,7 +37,7 @@ def mapper(value: int) -> rx.AsyncObservable[int]: assert obv.values == [(0, OnNext(10)), (0, OnNext(20)), (0, OnCompleted())] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_flat_map_monad(): m = rx.single(42) @@ -47,7 +50,7 @@ def mapper(x: int) -> AsyncObservable[int]: assert a == b -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_flat_map_monad_law_left_identity(): # return x >>= f is the same thing as f x @@ -62,7 +65,7 @@ def f(x: int) -> AsyncObservable[int]: assert a == b -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_flat_map_monad_law_right_identity(): # m >>= return is no different than just m. @@ -77,7 +80,7 @@ def mapper(x: str) -> AsyncObservable[str]: assert a == b -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_flat_map_monad_law_associativity(): # (m >>= f) >>= g is just like doing m >>= (\x -> f x >>= g) diff --git a/tests/test_forward_pipe.py b/tests/test_forward_pipe.py index e82fe58..1617e3c 100644 --- a/tests/test_forward_pipe.py +++ b/tests/test_forward_pipe.py @@ -12,14 +12,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_forward_pipe_map() -> None: xs = rx.from_iterable([1, 2, 3]) @@ -38,7 +40,7 @@ def mapper(value: int) -> int: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_forward_pipe_simple_pipe() -> None: xs = rx.from_iterable([1, 2, 3]) @@ -60,7 +62,7 @@ async def predicate(value: int) -> bool: assert obv.values == [(0, OnNext(20)), (0, OnNext(30)), (0, OnCompleted())] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_forward_pipe_complex_pipe() -> None: xs = rx.from_iterable([1, 2, 3]) result = [] diff --git a/tests/test_from_iterable.py b/tests/test_from_iterable.py index cd32ae2..b55653e 100644 --- a/tests/test_from_iterable.py +++ b/tests/test_from_iterable.py @@ -1,3 +1,4 @@ +import asyncio import pytest import aioreactive as rx @@ -5,14 +6,16 @@ from aioreactive.testing import AsyncTestObserver, VirtualTimeEventLoop -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_from_iterable_happy(): xs = rx.from_iterable([1, 2, 3]) @@ -26,7 +29,7 @@ async def test_from_iterable_happy(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_from_iterable_observer_throws(): xs = rx.from_iterable([1, 2, 3]) error = Exception("error") diff --git a/tests/test_map.py b/tests/test_map.py index d5cf1d0..0b404d5 100644 --- a/tests/test_map.py +++ b/tests/test_map.py @@ -10,14 +10,15 @@ from aioreactive.testing import VirtualTimeEventLoop -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_map_works(): xs: AsyncObservable[int] = rx.from_iterable([1, 2, 3]) values: list[int] = [] @@ -37,7 +38,7 @@ def mapper(value: int) -> int: assert values == [10, 20, 30] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_map_mapper_throws(): error = Exception("ex") exception = None @@ -65,7 +66,7 @@ def mapper(x: int): assert False -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_map_subscription_cancel(): xs: rx.AsyncSubject[int] = rx.AsyncSubject() sub: Optional[AsyncDisposable] = None @@ -90,7 +91,7 @@ async def asend(value: int) -> None: assert result == [100] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_mapi_works(): xs: AsyncObservable[int] = rx.from_iterable([1, 2, 3]) values: list[int] = [] diff --git a/tests/test_merge.py b/tests/test_merge.py index e782ec1..37e6fcb 100644 --- a/tests/test_merge.py +++ b/tests/test_merge.py @@ -1,3 +1,4 @@ +import asyncio import logging import pytest @@ -15,14 +16,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_merge_done(): xs: AsyncTestSubject[AsyncObservable[int]] = AsyncTestSubject() @@ -38,7 +41,7 @@ async def test_merge_done(): assert obv.values == [(0, OnNext(10)), (0, OnNext(20)), (0, OnCompleted())] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_merge_streams(): xs: AsyncTestSubject[AsyncObservable[int]] = AsyncTestSubject() s1: AsyncTestSubject[int] = AsyncTestSubject() @@ -75,7 +78,7 @@ async def test_merge_streams(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_merge_streams_concat(): s1: AsyncTestSubject[int] = AsyncTestSubject() s2 = rx.from_iterable([1, 2, 3]) diff --git a/tests/test_pipe.py b/tests/test_pipe.py index 5c953c9..2ce7287 100644 --- a/tests/test_pipe.py +++ b/tests/test_pipe.py @@ -15,14 +15,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type: ignore -def event_loop() -> Generator[VirtualTimeEventLoop, None, None]: - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_pipe_map() -> None: xs = rx.from_iterable([1, 2, 3]) @@ -41,7 +43,7 @@ def mapper(value: int) -> int: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_pipe_simple_pipe() -> None: xs = rx.from_iterable([1, 2, 3]) @@ -63,7 +65,7 @@ async def predicate(value: int) -> bool: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_pipe_complex_pipe() -> None: xs = rx.from_iterable([1, 2, 3]) result: List[int] = [] diff --git a/tests/test_reduce.py b/tests/test_reduce.py index 398227a..6343ea4 100644 --- a/tests/test_reduce.py +++ b/tests/test_reduce.py @@ -12,13 +12,13 @@ class MyException(Exception): pass -@pytest.fixture() -def event_loop(): - loop = VirtualTimeEventLoop() - try: - yield loop - finally: - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() + +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() def sync_sum(a: int, b: int) -> int: @@ -30,7 +30,7 @@ async def async_sum(a: int, b: int) -> int: return a + b -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_reduce(): xs = rx.from_iterable([1, 2, 3, 4]) observer = AsyncTestObserver() @@ -44,7 +44,7 @@ async def test_reduce(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_reduce_async(): xs = rx.from_iterable([1, 2, 3, 4]) observer = AsyncTestObserver() diff --git a/tests/test_scan.py b/tests/test_scan.py index 0ed251f..6ffd61b 100644 --- a/tests/test_scan.py +++ b/tests/test_scan.py @@ -13,13 +13,13 @@ class MyException(Exception): pass -@pytest.fixture() -def event_loop(): - loop = VirtualTimeEventLoop() - try: - yield loop - finally: - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() + +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() def sync_sum(a: int, b: int) -> int: @@ -31,7 +31,7 @@ async def async_sum(a: int, b: int) -> int: return a + b -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_scan(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() @@ -54,7 +54,7 @@ async def test_scan(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_scan_async(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() diff --git a/tests/test_single.py b/tests/test_single.py index e387a60..44b7b4b 100644 --- a/tests/test_single.py +++ b/tests/test_single.py @@ -14,14 +14,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_unit_happy(): xs = rx.single(42) @@ -30,7 +32,7 @@ async def test_unit_happy(): assert obv.values == [(0, OnNext(42)), (0, OnCompleted())] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_unit_observer_throws(): error = Exception("error") xs = rx.single(42) @@ -48,7 +50,7 @@ async def asend(value: int) -> None: assert obv.values == [(0, OnNext(42)), (0, OnError(error))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_unit_close(): xs = rx.single(42) sub: Optional[AsyncDisposable] = None @@ -69,7 +71,7 @@ async def asend(value: int) -> None: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_unit_happy_resolved_future(): fut: Awaitable[int] = asyncio.Future() xs = rx.from_async(fut) @@ -83,7 +85,7 @@ async def test_unit_happy_resolved_future(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_unit_happy_future_resolve(): fut: Awaitable[int] = asyncio.Future() xs = rx.from_async(fut) @@ -99,7 +101,7 @@ async def test_unit_happy_future_resolve(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_unit_future_exception(): fut: Awaitable[int] = asyncio.Future() ex = Exception("ex") @@ -113,7 +115,7 @@ async def test_unit_future_exception(): assert obv.values == [(0, OnError(ex))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_unit_future_cancel(): fut: Awaitable[int] = asyncio.Future() xs = rx.from_async(fut) diff --git a/tests/test_single_stream.py b/tests/test_single_stream.py index 262f538..c02e6f6 100644 --- a/tests/test_single_stream.py +++ b/tests/test_single_stream.py @@ -23,14 +23,16 @@ class MyException(Exception): pass -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_stream_happy(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() @@ -43,7 +45,7 @@ async def test_stream_happy(): assert sink.values == [(1, OnNext(10)), (2, OnNext(20)), (3, OnNext(30))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_throws(): ex = MyException("ex") xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() @@ -66,7 +68,7 @@ async def test_stream_throws(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_send_after_close(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() @@ -86,7 +88,7 @@ async def test_stream_send_after_close(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cancel(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() sub = None @@ -107,7 +109,7 @@ def mapper(value: int) -> int: assert sink.values == [(1, OnNext(100))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cancel_asend(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() sub: Optional[AsyncDisposable] = None @@ -132,7 +134,7 @@ def mapper(value: int) -> int: assert sink.values == [(1, OnNext(100))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cancel_mapper(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() sub: Optional[AsyncDisposable] = None @@ -155,7 +157,7 @@ async def mapper(value: int) -> int: assert sink.values == [(1, OnNext(100))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cancel_context(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() @@ -170,7 +172,7 @@ async def test_stream_cancel_context(): assert sink.values == [] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cold_send(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() @@ -188,7 +190,7 @@ async def asend(value: int) -> None: assert sink.values == [(10, OnNext(42)), (11, OnNext(20))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cold_throw(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() error = MyException() @@ -206,7 +208,7 @@ async def athrow(): assert sink.values == [(10, OnError(error))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cold_close(): xs: AsyncTestSingleSubject[int] = AsyncTestSingleSubject() diff --git a/tests/test_slice.py b/tests/test_slice.py index c19ee66..48e4b35 100644 --- a/tests/test_slice.py +++ b/tests/test_slice.py @@ -1,3 +1,4 @@ +import asyncio import logging import pytest @@ -11,14 +12,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_slice_special(): xs = AsyncRx.from_iterable([1, 2, 3, 4, 5]) @@ -36,7 +39,7 @@ async def test_slice_special(): ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_slice_step(): xs = AsyncRx.from_iterable([1, 2, 3, 4, 5]) diff --git a/tests/test_stream.py b/tests/test_stream.py index a068974..5c63b7c 100644 --- a/tests/test_stream.py +++ b/tests/test_stream.py @@ -3,7 +3,7 @@ from typing import Optional import pytest -from expression.core import pipe +from expression import pipe from expression.system.disposable import AsyncDisposable import aioreactive as rx @@ -22,14 +22,16 @@ class MyException(Exception): pass -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_stream_happy() -> None: xs: AsyncTestSubject[int] = AsyncTestSubject() @@ -42,7 +44,7 @@ async def test_stream_happy() -> None: assert obv.values == [(1, OnNext(10)), (2, OnNext(20)), (3, OnNext(30))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_throws() -> None: ex = MyException("ex") xs: AsyncTestSubject[int] = AsyncTestSubject() @@ -67,7 +69,7 @@ async def test_stream_throws() -> None: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_send_after_close() -> None: xs: AsyncTestSubject[int] = AsyncTestSubject() @@ -88,7 +90,7 @@ async def test_stream_send_after_close() -> None: ] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") # type: ignore async def test_stream_cancel() -> None: xs: AsyncTestSubject[int] = AsyncTestSubject() subscription: Optional[AsyncDisposable] = None @@ -107,7 +109,7 @@ def mapper(value: int) -> int: assert obv.values == [(1, OnNext(100))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") # type: ignore async def test_stream_cancel_asend() -> None: xs: AsyncTestSubject[int] = AsyncTestSubject() subscription: Optional[AsyncDisposable] = None @@ -132,7 +134,7 @@ def mapper(value: int) -> int: assert obv.values == [(1, OnNext(100))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") # type: ignore async def test_stream_cancel_mapper(): xs: AsyncTestSubject[int] = AsyncTestSubject() subscription: Optional[AsyncDisposable] = None @@ -156,7 +158,7 @@ def mapper(value: int) -> int: assert obv.values == [(100, OnNext(100))] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_stream_cancel_context(): xs: AsyncTestSubject[int] = AsyncTestSubject() diff --git a/tests/test_take.py b/tests/test_take.py index dc2b6a5..c95a0a4 100644 --- a/tests/test_take.py +++ b/tests/test_take.py @@ -1,3 +1,4 @@ +import asyncio import logging from asyncio import CancelledError @@ -13,14 +14,16 @@ logging.basicConfig(level=logging.DEBUG) -@pytest.fixture() # type:ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio + +@pytest.mark.asyncio(loop_scope="module") async def test_take_zero() -> None: xs = rx.from_iterable([1, 2, 3, 4, 5]) @@ -33,7 +36,7 @@ async def test_take_zero() -> None: assert obv.values == [(0, OnCompleted())] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_take_empty() -> None: xs: AsyncObservable[int] = rx.empty() @@ -46,7 +49,7 @@ async def test_take_empty() -> None: assert obv.values == [(0, OnCompleted())] -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_take_negative() -> None: xs = rx.from_iterable([1, 2, 3, 4, 5]) @@ -54,7 +57,7 @@ async def test_take_negative() -> None: pipe(xs, rx.take(-1)) -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_take_normal() -> None: xs = rx.from_iterable([1, 2, 3, 4, 5]) diff --git a/tests/test_with_latest_from.py b/tests/test_with_latest_from.py index 3e39850..0a05269 100644 --- a/tests/test_with_latest_from.py +++ b/tests/test_with_latest_from.py @@ -8,7 +8,6 @@ import aioreactive as rx from aioreactive.testing import ( AsyncTestObserver, - AsyncTestSubject, VirtualTimeEventLoop, ) from aioreactive.types import AsyncObservable, AsyncObserver @@ -16,15 +15,16 @@ log = logging.getLogger(__name__) logging.basicConfig(level=logging.DEBUG) +class EventLoopPolicy(asyncio.DefaultEventLoopPolicy): + def get_event_loop(self) -> asyncio.AbstractEventLoop: + return VirtualTimeEventLoop() -@pytest.fixture() # type: ignore -def event_loop(): - loop = VirtualTimeEventLoop() - yield loop - loop.close() +@pytest.fixture(scope="module") # type: ignore +def event_loop_policy(): + return EventLoopPolicy() -@pytest.mark.asyncio +@pytest.mark.asyncio(loop_scope="module") async def test_withlatestfrom_never_never(): xs: AsyncObservable[int] = rx.never() ys: AsyncObservable[int] = rx.never()