mirror of
https://github.com/aiogram/aiogram.git
synced 2025-12-06 07:50:32 +00:00
Support of Py3.14 (#1730)
Some checks failed
Tests / tests (macos-latest, 3.10) (push) Has been cancelled
Tests / tests (macos-latest, 3.11) (push) Has been cancelled
Tests / tests (macos-latest, 3.12) (push) Has been cancelled
Tests / tests (macos-latest, 3.13) (push) Has been cancelled
Tests / tests (macos-latest, 3.14) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.14) (push) Has been cancelled
Tests / tests (windows-latest, 3.10) (push) Has been cancelled
Tests / tests (windows-latest, 3.11) (push) Has been cancelled
Tests / tests (windows-latest, 3.12) (push) Has been cancelled
Tests / tests (windows-latest, 3.13) (push) Has been cancelled
Tests / tests (windows-latest, 3.14) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.11) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.11) (push) Has been cancelled
Some checks failed
Tests / tests (macos-latest, 3.10) (push) Has been cancelled
Tests / tests (macos-latest, 3.11) (push) Has been cancelled
Tests / tests (macos-latest, 3.12) (push) Has been cancelled
Tests / tests (macos-latest, 3.13) (push) Has been cancelled
Tests / tests (macos-latest, 3.14) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.10) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.11) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.12) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.13) (push) Has been cancelled
Tests / tests (ubuntu-latest, 3.14) (push) Has been cancelled
Tests / tests (windows-latest, 3.10) (push) Has been cancelled
Tests / tests (windows-latest, 3.11) (push) Has been cancelled
Tests / tests (windows-latest, 3.12) (push) Has been cancelled
Tests / tests (windows-latest, 3.13) (push) Has been cancelled
Tests / tests (windows-latest, 3.14) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (macos-latest, pypy3.11) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.10) (push) Has been cancelled
Tests / pypy-tests (ubuntu-latest, pypy3.11) (push) Has been cancelled
* Py3.14 support Bump .pre-commit-config.yaml Bump `mongo` feature deps Bump `proxy` feature dep Bump `test` feature deps Bump `dev` feature deps Set `aiohttp` max version `<3.14` Fix `test_isolation.py` tests Fix `test_storages.py` tests Add Py version limit `<3.15` (breaking changes possible) Add new `uvloop` starter to `Dispatcher.run_polling` Remove old `uvloop` `set_event_loop_policy` Remove `pytest-lazy-fixture` * Make `test` and `dev` features deps strong fixed * Add 1730.feature.rst * Remove unneeded `None` from `Dispatcher.run_polling` * Fix `macos-latest-pypy3.11` test `test_aiohtt_server.py` * Update `tests.yml` * Update `tests.yml`
This commit is contained in:
parent
0c6a705310
commit
4caf56814e
10 changed files with 77 additions and 64 deletions
7
.github/workflows/tests.yml
vendored
7
.github/workflows/tests.yml
vendored
|
|
@ -33,6 +33,7 @@ jobs:
|
||||||
- "3.11"
|
- "3.11"
|
||||||
- "3.12"
|
- "3.12"
|
||||||
- "3.13"
|
- "3.13"
|
||||||
|
- "3.14"
|
||||||
|
|
||||||
defaults:
|
defaults:
|
||||||
# Windows sucks. Force use bash instead of PowerShell
|
# Windows sucks. Force use bash instead of PowerShell
|
||||||
|
|
@ -74,13 +75,13 @@ jobs:
|
||||||
if: ${{ env.IS_WINDOWS == 'false' }}
|
if: ${{ env.IS_WINDOWS == 'false' }}
|
||||||
uses: shogo82148/actions-setup-redis@v1
|
uses: shogo82148/actions-setup-redis@v1
|
||||||
with:
|
with:
|
||||||
redis-version: 6
|
redis-version: "8"
|
||||||
|
|
||||||
- name: Setup mongodb
|
- name: Setup mongodb
|
||||||
if: ${{ env.IS_UBUNTU == 'true' }}
|
if: ${{ env.IS_UBUNTU == 'true' }}
|
||||||
uses: supercharge/mongodb-github-action@1.10.0
|
uses: supercharge/mongodb-github-action@1.12.0
|
||||||
with:
|
with:
|
||||||
mongodb-version: "7.0"
|
mongodb-version: "8"
|
||||||
mongodb-username: mongo
|
mongodb-username: mongo
|
||||||
mongodb-password: mongo
|
mongodb-password: mongo
|
||||||
mongodb-port: 27017
|
mongodb-port: 27017
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,6 @@
|
||||||
repos:
|
repos:
|
||||||
- repo: https://github.com/pre-commit/pre-commit-hooks
|
- repo: https://github.com/pre-commit/pre-commit-hooks
|
||||||
rev: v4.6.0
|
rev: v6.0.0
|
||||||
hooks:
|
hooks:
|
||||||
- id: "trailing-whitespace"
|
- id: "trailing-whitespace"
|
||||||
- id: "check-case-conflict"
|
- id: "check-case-conflict"
|
||||||
|
|
@ -20,6 +20,6 @@ repos:
|
||||||
files: &files '^(aiogram|tests|examples)'
|
files: &files '^(aiogram|tests|examples)'
|
||||||
|
|
||||||
- repo: https://github.com/astral-sh/ruff-pre-commit
|
- repo: https://github.com/astral-sh/ruff-pre-commit
|
||||||
rev: 'v0.13.3'
|
rev: 'v0.14.0'
|
||||||
hooks:
|
hooks:
|
||||||
- id: ruff
|
- id: ruff
|
||||||
|
|
|
||||||
6
CHANGES/1730.feature.rst
Normal file
6
CHANGES/1730.feature.rst
Normal file
|
|
@ -0,0 +1,6 @@
|
||||||
|
This PR updates the codebase to support Python 3.14.
|
||||||
|
|
||||||
|
- Updated project dep `aiohttp`
|
||||||
|
- Updated development deps
|
||||||
|
- Fixed tests to support Py3.14
|
||||||
|
- Refactored `uvloop` using due to deprecation of `asyncio.set_event_loop_police`
|
||||||
|
|
@ -1,6 +1,3 @@
|
||||||
import asyncio as _asyncio
|
|
||||||
from contextlib import suppress
|
|
||||||
|
|
||||||
from aiogram.dispatcher.flags import FlagGenerator
|
from aiogram.dispatcher.flags import FlagGenerator
|
||||||
|
|
||||||
from . import enums, methods, types
|
from . import enums, methods, types
|
||||||
|
|
@ -14,12 +11,6 @@ from .utils.magic_filter import MagicFilter
|
||||||
from .utils.text_decorations import html_decoration as html
|
from .utils.text_decorations import html_decoration as html
|
||||||
from .utils.text_decorations import markdown_decoration as md
|
from .utils.text_decorations import markdown_decoration as md
|
||||||
|
|
||||||
with suppress(ImportError):
|
|
||||||
import uvloop as _uvloop
|
|
||||||
|
|
||||||
_asyncio.set_event_loop_policy(_uvloop.EventLoopPolicy())
|
|
||||||
|
|
||||||
|
|
||||||
F = MagicFilter()
|
F = MagicFilter()
|
||||||
flags = FlagGenerator()
|
flags = FlagGenerator()
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -3,6 +3,7 @@ from __future__ import annotations
|
||||||
import asyncio
|
import asyncio
|
||||||
import contextvars
|
import contextvars
|
||||||
import signal
|
import signal
|
||||||
|
import sys
|
||||||
import warnings
|
import warnings
|
||||||
from asyncio import CancelledError, Event, Future, Lock
|
from asyncio import CancelledError, Event, Future, Lock
|
||||||
from collections.abc import AsyncGenerator, Awaitable
|
from collections.abc import AsyncGenerator, Awaitable
|
||||||
|
|
@ -656,16 +657,28 @@ class Dispatcher(Router):
|
||||||
:return:
|
:return:
|
||||||
"""
|
"""
|
||||||
with suppress(KeyboardInterrupt):
|
with suppress(KeyboardInterrupt):
|
||||||
return asyncio.run(
|
coro = self.start_polling(
|
||||||
self.start_polling(
|
*bots,
|
||||||
*bots,
|
**kwargs,
|
||||||
**kwargs,
|
polling_timeout=polling_timeout,
|
||||||
polling_timeout=polling_timeout,
|
handle_as_tasks=handle_as_tasks,
|
||||||
handle_as_tasks=handle_as_tasks,
|
backoff_config=backoff_config,
|
||||||
backoff_config=backoff_config,
|
allowed_updates=allowed_updates,
|
||||||
allowed_updates=allowed_updates,
|
handle_signals=handle_signals,
|
||||||
handle_signals=handle_signals,
|
close_bot_session=close_bot_session,
|
||||||
close_bot_session=close_bot_session,
|
tasks_concurrency_limit=tasks_concurrency_limit,
|
||||||
tasks_concurrency_limit=tasks_concurrency_limit,
|
|
||||||
),
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
try:
|
||||||
|
import uvloop
|
||||||
|
|
||||||
|
except ImportError:
|
||||||
|
return asyncio.run(coro)
|
||||||
|
|
||||||
|
else:
|
||||||
|
if sys.version_info >= (3, 11):
|
||||||
|
with asyncio.Runner(loop_factory=uvloop.new_event_loop) as runner:
|
||||||
|
return runner.run(coro)
|
||||||
|
else:
|
||||||
|
uvloop.install()
|
||||||
|
return asyncio.run(coro)
|
||||||
|
|
|
||||||
|
|
@ -6,7 +6,7 @@ build-backend = "hatchling.build"
|
||||||
name = "aiogram"
|
name = "aiogram"
|
||||||
description = 'Modern and fully asynchronous framework for Telegram Bot API'
|
description = 'Modern and fully asynchronous framework for Telegram Bot API'
|
||||||
readme = "README.rst"
|
readme = "README.rst"
|
||||||
requires-python = ">=3.10"
|
requires-python = ">=3.10,<3.15"
|
||||||
license = "MIT"
|
license = "MIT"
|
||||||
authors = [
|
authors = [
|
||||||
{ name = "Alex Root Junior", email = "jroot.junior@gmail.com" },
|
{ name = "Alex Root Junior", email = "jroot.junior@gmail.com" },
|
||||||
|
|
@ -34,6 +34,7 @@ classifiers = [
|
||||||
"Programming Language :: Python :: 3.11",
|
"Programming Language :: Python :: 3.11",
|
||||||
"Programming Language :: Python :: 3.12",
|
"Programming Language :: Python :: 3.12",
|
||||||
"Programming Language :: Python :: 3.13",
|
"Programming Language :: Python :: 3.13",
|
||||||
|
"Programming Language :: Python :: 3.14",
|
||||||
"Programming Language :: Python :: Implementation :: PyPy",
|
"Programming Language :: Python :: Implementation :: PyPy",
|
||||||
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
"Topic :: Software Development :: Libraries :: Application Frameworks",
|
||||||
"Topic :: Software Development :: Libraries :: Python Modules",
|
"Topic :: Software Development :: Libraries :: Python Modules",
|
||||||
|
|
@ -41,7 +42,7 @@ classifiers = [
|
||||||
]
|
]
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"magic-filter>=1.0.12,<1.1",
|
"magic-filter>=1.0.12,<1.1",
|
||||||
"aiohttp>=3.9.0,<3.13",
|
"aiohttp>=3.9.0,<3.14",
|
||||||
"pydantic>=2.4.1,<2.13",
|
"pydantic>=2.4.1,<2.13",
|
||||||
"aiofiles>=23.2.1,<24.2",
|
"aiofiles>=23.2.1,<24.2",
|
||||||
"certifi>=2023.7.22",
|
"certifi>=2023.7.22",
|
||||||
|
|
@ -62,11 +63,11 @@ redis = [
|
||||||
"redis[hiredis]>=6.2.0,<7",
|
"redis[hiredis]>=6.2.0,<7",
|
||||||
]
|
]
|
||||||
mongo = [
|
mongo = [
|
||||||
"motor>=3.3.2,<3.7.0",
|
"motor>=3.3.2,<3.8",
|
||||||
"pymongo>4.5,<4.11",
|
"pymongo>4.5,<4.16",
|
||||||
]
|
]
|
||||||
proxy = [
|
proxy = [
|
||||||
"aiohttp-socks~=0.8.3",
|
"aiohttp-socks~=0.10.1",
|
||||||
]
|
]
|
||||||
i18n = [
|
i18n = [
|
||||||
"Babel>=2.13.0,<3",
|
"Babel>=2.13.0,<3",
|
||||||
|
|
@ -78,17 +79,15 @@ signature = [
|
||||||
"cryptography>=46.0.0",
|
"cryptography>=46.0.0",
|
||||||
]
|
]
|
||||||
test = [
|
test = [
|
||||||
"pytest~=7.4.2",
|
"pytest==8.4.2",
|
||||||
"pytest-html~=4.0.2",
|
"pytest-html==4.1.1",
|
||||||
"pytest-asyncio~=0.21.1",
|
"pytest-mock==3.15.1",
|
||||||
"pytest-lazy-fixture~=0.6.3",
|
"pytest-mypy==1.0.1",
|
||||||
"pytest-mock~=3.12.0",
|
"pytest-cov==7.0.0",
|
||||||
"pytest-mypy~=0.10.3",
|
"pytest-aiohttp==1.1.0",
|
||||||
"pytest-cov~=4.1.0",
|
"aresponses==3.0.0",
|
||||||
"pytest-aiohttp~=1.0.5",
|
"pytz==2025.2",
|
||||||
"aresponses~=2.1.6",
|
"pycryptodomex==3.23.0",
|
||||||
"pytz~=2025.2",
|
|
||||||
"pycryptodomex~=3.23.0",
|
|
||||||
]
|
]
|
||||||
docs = [
|
docs = [
|
||||||
"Sphinx~=8.0.2",
|
"Sphinx~=8.0.2",
|
||||||
|
|
@ -104,14 +103,14 @@ docs = [
|
||||||
"sphinxcontrib-towncrier~=0.4.0a0",
|
"sphinxcontrib-towncrier~=0.4.0a0",
|
||||||
]
|
]
|
||||||
dev = [
|
dev = [
|
||||||
"black~=25.9.0",
|
"black==25.9.0",
|
||||||
"isort~=6.1.0",
|
"isort==6.1.0",
|
||||||
"ruff~=0.13.3",
|
"ruff==0.14.0",
|
||||||
"mypy~=1.10.1",
|
"mypy==1.10.1",
|
||||||
"toml~=0.10.2",
|
"toml==0.10.2",
|
||||||
"pre-commit~=4.3.0",
|
"pre-commit==4.3.0",
|
||||||
"packaging~=24.1",
|
"packaging==25.0",
|
||||||
"motor-types~=1.0.0b4",
|
"motor-types==1.0.0b4",
|
||||||
]
|
]
|
||||||
|
|
||||||
[project.urls]
|
[project.urls]
|
||||||
|
|
|
||||||
|
|
@ -39,7 +39,7 @@ def pytest_configure(config):
|
||||||
config.addinivalue_line("markers", "redis: marked tests require redis connection to run")
|
config.addinivalue_line("markers", "redis: marked tests require redis connection to run")
|
||||||
config.addinivalue_line("markers", "mongo: marked tests require mongo connection to run")
|
config.addinivalue_line("markers", "mongo: marked tests require mongo connection to run")
|
||||||
|
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32" and sys.version_info < (3, 14):
|
||||||
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
asyncio.set_event_loop_policy(asyncio.WindowsSelectorEventLoopPolicy())
|
||||||
else:
|
else:
|
||||||
asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
|
asyncio.set_event_loop_policy(asyncio.DefaultEventLoopPolicy())
|
||||||
|
|
@ -186,6 +186,16 @@ async def dispatcher():
|
||||||
await dp.emit_shutdown()
|
await dp.emit_shutdown()
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def storage(request):
|
||||||
|
return request.getfixturevalue(request.param)
|
||||||
|
|
||||||
|
|
||||||
|
@pytest.fixture()
|
||||||
|
def isolation(request):
|
||||||
|
return request.getfixturevalue(request.param)
|
||||||
|
|
||||||
|
|
||||||
# @pytest.fixture(scope="session")
|
# @pytest.fixture(scope="session")
|
||||||
# def event_loop_policy(request):
|
# def event_loop_policy(request):
|
||||||
# if sys.platform == "win32":
|
# if sys.platform == "win32":
|
||||||
|
|
|
||||||
|
|
@ -8,11 +8,8 @@ from aiogram.fsm.storage.redis import RedisEventIsolation, RedisStorage
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"isolation",
|
"isolation",
|
||||||
[
|
["redis_isolation", "lock_isolation", "disabled_isolation"],
|
||||||
pytest.lazy_fixture("redis_isolation"),
|
indirect=True,
|
||||||
pytest.lazy_fixture("lock_isolation"),
|
|
||||||
pytest.lazy_fixture("disabled_isolation"),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
class TestIsolations:
|
class TestIsolations:
|
||||||
async def test_lock(
|
async def test_lock(
|
||||||
|
|
|
||||||
|
|
@ -8,12 +8,8 @@ from aiogram.fsm.storage.base import BaseStorage, StorageKey
|
||||||
|
|
||||||
@pytest.mark.parametrize(
|
@pytest.mark.parametrize(
|
||||||
"storage",
|
"storage",
|
||||||
[
|
["memory_storage", "redis_storage", "mongo_storage", "pymongo_storage"],
|
||||||
pytest.lazy_fixture("redis_storage"),
|
indirect=True,
|
||||||
pytest.lazy_fixture("mongo_storage"),
|
|
||||||
pytest.lazy_fixture("pymongo_storage"),
|
|
||||||
pytest.lazy_fixture("memory_storage"),
|
|
||||||
],
|
|
||||||
)
|
)
|
||||||
class TestStorages:
|
class TestStorages:
|
||||||
async def test_set_state(self, storage: BaseStorage, storage_key: StorageKey):
|
async def test_set_state(self, storage: BaseStorage, storage_key: StorageKey):
|
||||||
|
|
|
||||||
|
|
@ -185,8 +185,8 @@ class TestSimpleRequestHandler:
|
||||||
handler_event.clear()
|
handler_event.clear()
|
||||||
resp = await self.make_reqest(client=client)
|
resp = await self.make_reqest(client=client)
|
||||||
assert resp.status == 200
|
assert resp.status == 200
|
||||||
await asyncio.wait_for(handler_event.wait(), timeout=1)
|
await asyncio.wait_for(handler_event.wait(), timeout=3)
|
||||||
await asyncio.wait_for(method_called_event.wait(), timeout=1)
|
await asyncio.wait_for(method_called_event.wait(), timeout=3)
|
||||||
# Python 3.12 had some changes to asyncio which make it quite a bit faster. But
|
# Python 3.12 had some changes to asyncio which make it quite a bit faster. But
|
||||||
# probably because of that the assert_awaited call is consistently scheduled before the
|
# probably because of that the assert_awaited call is consistently scheduled before the
|
||||||
# silent_call_request call - failing the test. So we wait for the method to be called
|
# silent_call_request call - failing the test. So we wait for the method to be called
|
||||||
Loading…
Add table
Add a link
Reference in a new issue