From e4a3173dc749fd9a544e31aebd8004cdc747ae15 Mon Sep 17 00:00:00 2001 From: Paillat Date: Thu, 17 Apr 2025 17:55:50 +0200 Subject: [PATCH 1/8] :sparkles: Update to use python 3.14 --- .github/workflows/docs-checks.yml | 2 +- .github/workflows/docs-localization-download.yml | 2 +- .github/workflows/docs-localization-upload.yml | 2 +- .github/workflows/lib-checks.yml | 10 +++++----- .github/workflows/release.yml | 2 +- .readthedocs.yml | 2 +- README.rst | 2 +- pyproject.toml | 1 + 8 files changed, 12 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docs-checks.yml b/.github/workflows/docs-checks.yml index a86e154832..68507c4a1b 100644 --- a/.github/workflows/docs-checks.yml +++ b/.github/workflows/docs-checks.yml @@ -40,7 +40,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/docs.txt" check-latest: true diff --git a/.github/workflows/docs-localization-download.yml b/.github/workflows/docs-localization-download.yml index ab743a40db..84f46220f2 100644 --- a/.github/workflows/docs-localization-download.yml +++ b/.github/workflows/docs-localization-download.yml @@ -21,7 +21,7 @@ jobs: - name: "Install Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/_locale.txt" - name: "Install Dependencies" diff --git a/.github/workflows/docs-localization-upload.yml b/.github/workflows/docs-localization-upload.yml index 7667fc68af..3384f3223f 100644 --- a/.github/workflows/docs-localization-upload.yml +++ b/.github/workflows/docs-localization-upload.yml @@ -26,7 +26,7 @@ jobs: - name: "Install Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/_locale.txt" - name: "Install Dependencies" diff --git a/.github/workflows/lib-checks.yml b/.github/workflows/lib-checks.yml index f1d937f9cd..f5edede82e 100644 --- a/.github/workflows/lib-checks.yml +++ b/.github/workflows/lib-checks.yml @@ -36,7 +36,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/dev.txt" - name: "Install dependencies" @@ -56,7 +56,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/dev.txt" - name: "Install dependencies" @@ -74,7 +74,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/dev.txt" - name: "Install dependencies" @@ -98,7 +98,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v5 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/dev.txt" - name: "Install dependencies" @@ -120,7 +120,7 @@ jobs: strategy: matrix: os: [ubuntu-latest, macos-latest, windows-latest] - python-version: ["3.9", "3.10", "3.11", "3.12", "3.13"] + python-version: ["3.9", "3.10", "3.11", "3.12", "3.13", "3.14"] exclude: - { python-version: "3.9", os: "macos-latest" } include: diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index c94658c2fb..82953a751c 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -92,7 +92,7 @@ jobs: version-branch-name: ${{ needs.pre_config.outputs.branch_name }} ref: ${{ github.ref_name }} repository: ${{ github.repository }} - python-version: "3.13" + python-version: "3.14" release-requirements: "requirements/_release.txt" version: ${{ needs.pre_config.outputs.version }} is-rc: ${{ needs.pre_config.outputs.is_rc }} diff --git a/.readthedocs.yml b/.readthedocs.yml index 1b4720a322..08e9c920be 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,7 +4,7 @@ formats: [] build: os: ubuntu-22.04 tools: - python: "3.13" + python: "3.14" sphinx: configuration: docs/conf.py diff --git a/README.rst b/README.rst index 4518a946ed..b840ecfbf5 100644 --- a/README.rst +++ b/README.rst @@ -31,7 +31,7 @@ Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for D Note ---- -Pycord supports Python ``3.9`` - ``3.13`` +Pycord supports Python ``3.9`` - ``3.14`` Key Features ------------ diff --git a/pyproject.toml b/pyproject.toml index b9fd493eba..b2d9220cf4 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -26,6 +26,7 @@ classifiers = [ "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", "Programming Language :: Python :: 3.13", + "Programming Language :: Python :: 3.14", "Topic :: Internet", "Topic :: Software Development :: Libraries", "Topic :: Software Development :: Libraries :: Python Modules", From db16e2593e2849f00b69f711de9953d7b3be172d Mon Sep 17 00:00:00 2001 From: Paillat-dev Date: Thu, 9 Oct 2025 13:01:52 +0200 Subject: [PATCH 2/8] :rewind: Revert .readthedocs.yml python version bump --- .readthedocs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.readthedocs.yml b/.readthedocs.yml index 08e9c920be..1b4720a322 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -4,7 +4,7 @@ formats: [] build: os: ubuntu-22.04 tools: - python: "3.14" + python: "3.13" sphinx: configuration: docs/conf.py From 0013089517b14c56d833f9db1df0d9bb81aad7ab Mon Sep 17 00:00:00 2001 From: Paillat-dev Date: Thu, 9 Oct 2025 13:04:38 +0200 Subject: [PATCH 3/8] :memo: CHANGELOG.md --- CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 01e0f2b8fd..64ae6693c5 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -28,6 +28,8 @@ These changes are available on the `master` branch, but have not yet been releas - Adds pre-typed and pre-constructed with select_type `ui.Select` aliases for the different select types: `ui.StringSelect`, `ui.UserSelect`, `ui.RoleSelect`, `ui.MentionableSelect`, and `ui.ChannelSelect`. +- Support for **Python 3.14**. + ([#2948](https://github.com/Pycord-Development/pycord/pull/2948)) ### Changed From c158bb264d6bf7415a37f8a05a7dd96d9d29df7b Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Wed, 22 Oct 2025 12:34:40 +0200 Subject: [PATCH 4/8] chore: fix changelog position Signed-off-by: Lala Sabathil --- CHANGELOG.md | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 974f7a9bbc..6a4e7edecb 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -12,6 +12,9 @@ These changes are available on the `master` branch, but have not yet been releas ### Added +- Support for **Python 3.14**. + ([#2948](https://github.com/Pycord-Development/pycord/pull/2948)) + ### Changed ### Fixed @@ -42,8 +45,6 @@ These changes are available on the `master` branch, but have not yet been releas - Adds pre-typed and pre-constructed with select_type `ui.Select` aliases for the different select types: `ui.StringSelect`, `ui.UserSelect`, `ui.RoleSelect`, `ui.MentionableSelect`, and `ui.ChannelSelect`. -- Support for **Python 3.14**. - ([#2948](https://github.com/Pycord-Development/pycord/pull/2948)) - Added `store` parameter to `View` and `Modal` classes. ([#2904](https://github.com/Pycord-Development/pycord/pull/2904/)) - Added `Webhook.parent` and `Webhook.from_interaction` From 820e5fdf2f5e1dd0561fe3e457eb474bb0bc46c6 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Sat, 1 Nov 2025 15:10:35 +0100 Subject: [PATCH 5/8] fix: missing changes --- .github/workflows/docs-json-export.yml | 2 +- pyproject.toml | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/.github/workflows/docs-json-export.yml b/.github/workflows/docs-json-export.yml index 869b1774d7..e63c95f3c2 100644 --- a/.github/workflows/docs-json-export.yml +++ b/.github/workflows/docs-json-export.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-python@v6 id: setup-python with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/docs.txt" check-latest: true diff --git a/pyproject.toml b/pyproject.toml index 8b9a1fbc71..db7c91b225 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -12,7 +12,7 @@ authors = [ ] description = "A Python wrapper for the Discord API" readme = {content-type = "text/x-rst", file = "README.rst"} -requires-python = ">=3.10, <3.14" +requires-python = ">=3.10, <3.15" license = "MIT" license-files = ["LICENSE"] classifiers = [ @@ -68,7 +68,7 @@ voice = {file = "requirements/voice.txt"} [tool.setuptools_scm] [tool.black] -target-version = ['py310', 'py311', 'py312', 'py313'] +target-version = ['py310', 'py311', 'py312', 'py313', 'py314'] [tool.isort] profile = "black" From 7b5aad032edb2bfc08a3131a28726c092d206882 Mon Sep 17 00:00:00 2001 From: Lala Sabathil Date: Sat, 1 Nov 2025 15:24:42 +0100 Subject: [PATCH 6/8] fix(actions): Stick to 3.13 for docs for now until rtd support 3.14 Ref: https://github.com/readthedocs/readthedocs.org/issues/12523#issuecomment-3436862569 --- .github/workflows/docs-checks.yml | 2 +- .github/workflows/docs-json-export.yml | 2 +- .github/workflows/docs-localization-download.yml | 2 +- .github/workflows/docs-localization-upload.yml | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/workflows/docs-checks.yml b/.github/workflows/docs-checks.yml index 8e35f953cb..fa224a9525 100644 --- a/.github/workflows/docs-checks.yml +++ b/.github/workflows/docs-checks.yml @@ -40,7 +40,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v6 with: - python-version: "3.14" + python-version: "3.13" cache: "pip" cache-dependency-path: "requirements/docs.txt" check-latest: true diff --git a/.github/workflows/docs-json-export.yml b/.github/workflows/docs-json-export.yml index e63c95f3c2..869b1774d7 100644 --- a/.github/workflows/docs-json-export.yml +++ b/.github/workflows/docs-json-export.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-python@v6 id: setup-python with: - python-version: "3.14" + python-version: "3.13" cache: "pip" cache-dependency-path: "requirements/docs.txt" check-latest: true diff --git a/.github/workflows/docs-localization-download.yml b/.github/workflows/docs-localization-download.yml index ef56afd5b2..90d025e3ff 100644 --- a/.github/workflows/docs-localization-download.yml +++ b/.github/workflows/docs-localization-download.yml @@ -21,7 +21,7 @@ jobs: - name: "Install Python" uses: actions/setup-python@v6 with: - python-version: "3.14" + python-version: "3.13" cache: "pip" cache-dependency-path: "requirements/_locale.txt" - name: "Install Dependencies" diff --git a/.github/workflows/docs-localization-upload.yml b/.github/workflows/docs-localization-upload.yml index 7882066aeb..c79fff65eb 100644 --- a/.github/workflows/docs-localization-upload.yml +++ b/.github/workflows/docs-localization-upload.yml @@ -26,7 +26,7 @@ jobs: - name: "Install Python" uses: actions/setup-python@v6 with: - python-version: "3.14" + python-version: "3.13" cache: "pip" cache-dependency-path: "requirements/_locale.txt" - name: "Install Dependencies" From 4dacf6fc3a7cac194aa3a844fb044adb221418ec Mon Sep 17 00:00:00 2001 From: Paillat-dev Date: Wed, 18 Mar 2026 11:24:28 +0100 Subject: [PATCH 7/8] chore: Docs should support 3.14 by now --- .github/workflows/docs-checks.yml | 4 ++-- .github/workflows/docs-json-export.yml | 4 ++-- .github/workflows/docs-localization-download.yml | 4 ++-- .github/workflows/docs-localization-upload.yml | 6 +++--- .readthedocs.yml | 4 ++-- 5 files changed, 11 insertions(+), 11 deletions(-) diff --git a/.github/workflows/docs-checks.yml b/.github/workflows/docs-checks.yml index 85bfc8267d..65b1b68338 100644 --- a/.github/workflows/docs-checks.yml +++ b/.github/workflows/docs-checks.yml @@ -8,7 +8,7 @@ on: - "requirements/**" - "*.toml" - "*.py" - branches: [master] + branches: [ master ] pull_request: paths: - "discord/**" @@ -40,7 +40,7 @@ jobs: - name: "Setup Python" uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/docs.txt" check-latest: true diff --git a/.github/workflows/docs-json-export.yml b/.github/workflows/docs-json-export.yml index d9e5904273..f4f1f8d5a7 100644 --- a/.github/workflows/docs-json-export.yml +++ b/.github/workflows/docs-json-export.yml @@ -18,7 +18,7 @@ jobs: uses: actions/setup-python@v6 id: setup-python with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/docs.txt" check-latest: true @@ -45,7 +45,7 @@ jobs: run: | head -n 40 docs.json || tail -n 40 docs.json - name: Output artifact ID - run: | + run: | echo "artifact-id=${{ steps.artifact-upload.outputs.artifact-id }}" >> $GITHUB_OUTPUT echo "artifact-url=${{ steps.artifact-upload.outputs.artifact-url }}" >> $GITHUB_OUTPUT echo "::notice::Artifact uploaded: ${{ steps.artifact-upload.outputs.artifact-url }}" diff --git a/.github/workflows/docs-localization-download.yml b/.github/workflows/docs-localization-download.yml index d574d8fb7a..d38c43764c 100644 --- a/.github/workflows/docs-localization-download.yml +++ b/.github/workflows/docs-localization-download.yml @@ -21,7 +21,7 @@ jobs: - name: "Install Python" uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/_locale.txt" - name: "Install Dependencies" @@ -69,7 +69,7 @@ jobs: pr: name: "PR operations" - needs: [download] + needs: [ download ] runs-on: ubuntu-latest environment: translations steps: diff --git a/.github/workflows/docs-localization-upload.yml b/.github/workflows/docs-localization-upload.yml index 3d2c586e5f..b5757815d3 100644 --- a/.github/workflows/docs-localization-upload.yml +++ b/.github/workflows/docs-localization-upload.yml @@ -5,11 +5,11 @@ on: paths: - "discord/**" - "docs/**" - branches: [master] + branches: [ master ] workflow_dispatch: schedule: - cron: "0 0 * * 1" - + permissions: write-all jobs: @@ -26,7 +26,7 @@ jobs: - name: "Install Python" uses: actions/setup-python@v6 with: - python-version: "3.13" + python-version: "3.14" cache: "pip" cache-dependency-path: "requirements/_locale.txt" - name: "Install Dependencies" diff --git a/.readthedocs.yml b/.readthedocs.yml index ee1beb81d4..54236d5039 100644 --- a/.readthedocs.yml +++ b/.readthedocs.yml @@ -1,10 +1,10 @@ version: 2 -formats: [] +formats: [ ] build: os: ubuntu-22.04 tools: - python: "3.13" + python: "3.14" sphinx: configuration: docs/conf.py From c73d4ce947937501dc75bd3fe6ffcae40d96f12f Mon Sep 17 00:00:00 2001 From: Paillat Date: Fri, 27 Mar 2026 23:52:10 +0100 Subject: [PATCH 8/8] fix: Update event loop retrieval to support Python 3.14+ --- discord/client.py | 12 +++++++++--- discord/ext/commands/cooldowns.py | 3 ++- discord/ext/tasks/__init__.py | 8 ++++---- discord/http.py | 4 ++-- discord/ui/modal.py | 4 ++-- discord/utils.py | 18 ++++++++++++++++++ 6 files changed, 37 insertions(+), 12 deletions(-) diff --git a/discord/client.py b/discord/client.py index 211532d68d..f227ccf1df 100644 --- a/discord/client.py +++ b/discord/client.py @@ -70,7 +70,13 @@ from .threads import Thread from .ui.view import BaseView from .user import ClientUser, User -from .utils import _D, _FETCHABLE, MISSING, warn_if_voice_dependencies_missing +from .utils import ( + _D, + _FETCHABLE, + MISSING, + _get_event_loop, + warn_if_voice_dependencies_missing, +) from .webhook import Webhook from .widget import Widget @@ -147,7 +153,7 @@ class Client: loop: Optional[:class:`asyncio.AbstractEventLoop`] The :class:`asyncio.AbstractEventLoop` to use for asynchronous operations. Defaults to ``None``, in which case the default event loop is used via - :func:`asyncio.get_event_loop()`. + :func:`asyncio.get_event_loop()` if it exists or one is created via :func:`asyncio.new_event_loop()`. connector: Optional[:class:`aiohttp.BaseConnector`] The connector to use for connection pooling. proxy: Optional[:class:`str`] @@ -245,7 +251,7 @@ def __init__( # self.ws is set in the connect method self.ws: DiscordWebSocket = None # type: ignore self.loop: asyncio.AbstractEventLoop = ( - asyncio.get_event_loop() if loop is None else loop + _get_event_loop() if loop is None else loop ) self._listeners: dict[str, list[tuple[asyncio.Future, Callable[..., bool]]]] = ( {} diff --git a/discord/ext/commands/cooldowns.py b/discord/ext/commands/cooldowns.py index 6e58d37f7a..7504eed7c8 100644 --- a/discord/ext/commands/cooldowns.py +++ b/discord/ext/commands/cooldowns.py @@ -32,6 +32,7 @@ import discord.abc from discord.enums import Enum +from discord.utils import _get_event_loop from ...abc import PrivateChannel from .errors import MaxConcurrencyReached @@ -308,7 +309,7 @@ class _Semaphore: def __init__(self, number: int) -> None: self.value: int = number - self.loop: asyncio.AbstractEventLoop = asyncio.get_event_loop() + self.loop: asyncio.AbstractEventLoop = _get_event_loop() self._waiters: Deque[asyncio.Future] = deque() def __repr__(self) -> str: diff --git a/discord/ext/tasks/__init__.py b/discord/ext/tasks/__init__.py index 9bdde87f23..6bb719c67f 100644 --- a/discord/ext/tasks/__init__.py +++ b/discord/ext/tasks/__init__.py @@ -38,7 +38,7 @@ import discord from discord.backoff import ExponentialBackoff -from discord.utils import MISSING +from discord.utils import MISSING, _get_event_loop __all__ = ("loop",) @@ -384,7 +384,7 @@ def start(self, *args: Any, **kwargs: Any) -> asyncio.Task[None]: args = (self._injected, *args) if self.loop is MISSING: - self.loop = asyncio.get_event_loop() + self.loop = _get_event_loop() self._task = self.loop.create_task(self._loop(*args, **kwargs)) return self._task @@ -825,8 +825,8 @@ def loop( using an exponential back-off algorithm similar to the one used in :meth:`discord.Client.connect`. loop: :class:`asyncio.AbstractEventLoop` - The loop to use to register the task, if not given - defaults to :func:`asyncio.get_event_loop`. + The loop to use to register the task, if not given the default event loop is used via + :func:`asyncio.get_event_loop()` if it exists or one is created via :func:`asyncio.new_event_loop()`. overlap: Union[:class:`bool`, :class:`int`] Controls whether overlapping executions of the task loop are allowed. Set to False (default) to run iterations one at a time, True for unlimited overlap, or an int to cap the number of concurrent runs. diff --git a/discord/http.py b/discord/http.py index 0717feadf5..fc6ffb22c3 100644 --- a/discord/http.py +++ b/discord/http.py @@ -55,7 +55,7 @@ from .file import VoiceMessage from .gateway import DiscordClientWebSocketResponse from .soundboard import PartialSoundboardSound, SoundboardSound -from .utils import MISSING +from .utils import MISSING, _get_event_loop _log = logging.getLogger(__name__) @@ -192,7 +192,7 @@ def __init__( unsync_clock: bool = True, ) -> None: self.loop: asyncio.AbstractEventLoop = ( - asyncio.get_event_loop() if loop is None else loop + _get_event_loop() if loop is None else loop ) self.connector = connector self.__session: aiohttp.ClientSession = MISSING # filled in static_login diff --git a/discord/ui/modal.py b/discord/ui/modal.py index 6bb3a21d6a..67c68913f9 100644 --- a/discord/ui/modal.py +++ b/discord/ui/modal.py @@ -33,7 +33,7 @@ from typing import TYPE_CHECKING, Any, Iterator, TypeVar from ..enums import ComponentType -from ..utils import find +from ..utils import _get_event_loop, find from .core import ItemInterface from .input_text import InputText from .item import ModalItem @@ -91,7 +91,7 @@ def __init__( for item in children: self.add_item(item) self._title = title - self.loop = asyncio.get_event_loop() + self.loop = _get_event_loop() def __repr__(self) -> str: attrs = " ".join( diff --git a/discord/utils.py b/discord/utils.py index cc6d9d3b19..d2e382fc53 100644 --- a/discord/utils.py +++ b/discord/utils.py @@ -1665,3 +1665,21 @@ def warn_if_voice_dependencies_missing() -> None: deps, "is" if len(missing) == 1 else "are", ) + + +def _get_event_loop() -> asyncio.AbstractEventLoop: + """Get the current event loop, creating one if necessary. + + Returns + ------- + asyncio.AbstractEventLoop + The current event loop. + """ + if sys.version_info >= (3, 14): + try: + loop = asyncio.get_running_loop() + except RuntimeError: + loop = asyncio.new_event_loop() + asyncio.set_event_loop(loop) + return loop + return asyncio.get_event_loop()