Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 2 additions & 2 deletions .github/workflows/docs-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ on:
- "requirements/**"
- "*.toml"
- "*.py"
branches: [master]
branches: [ master ]
pull_request:
paths:
- "discord/**"
Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions .github/workflows/docs-json-export.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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 }}"
4 changes: 2 additions & 2 deletions .github/workflows/docs-localization-download.yml
Original file line number Diff line number Diff line change
Expand Up @@ -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"
Expand Down Expand Up @@ -69,7 +69,7 @@ jobs:

pr:
name: "PR operations"
needs: [download]
needs: [ download ]
runs-on: ubuntu-latest
environment: translations
steps:
Expand Down
6 changes: 3 additions & 3 deletions .github/workflows/docs-localization-upload.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,11 +5,11 @@ on:
paths:
- "discord/**"
- "docs/**"
branches: [master]
branches: [ master ]
workflow_dispatch:
schedule:
- cron: "0 0 * * 1"

permissions: write-all

jobs:
Expand All @@ -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"
Expand Down
12 changes: 6 additions & 6 deletions .github/workflows/lib-checks.yml
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ jobs:
- name: "Setup Python"
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: "Install dependencies"
Expand All @@ -56,7 +56,7 @@ jobs:
- name: "Setup Python"
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: "Install dependencies"
Expand All @@ -74,7 +74,7 @@ jobs:
- name: "Setup Python"
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: "Install dependencies"
Expand All @@ -98,7 +98,7 @@ jobs:
- name: "Setup Python"
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: "Install dependencies"
Expand All @@ -124,7 +124,7 @@ jobs:
- name: "Setup Python"
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"
cache: "pip"
cache-dependency-path: "pyproject.toml"
- name: "Install dependencies"
Expand All @@ -141,7 +141,7 @@ jobs:
strategy:
matrix:
os: [ ubuntu-latest, windows-latest, macos-latest ]
python-version: [ "3.10", "3.11", "3.12", "3.13" ]
python-version: [ "3.10", "3.11", "3.12", "3.13", "3.14" ]
steps:
- name: "Checkout Repository"
uses: actions/checkout@v6
Expand Down
2 changes: 1 addition & 1 deletion .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -136,7 +136,7 @@ jobs:
id: python-setup
uses: actions/setup-python@v6
with:
python-version: "3.13"
python-version: "3.14"
cache: "pip"
cache-dependency-path: "requirements/_release.txt"
- name: "Install Release Dependencies"
Expand Down
4 changes: 2 additions & 2 deletions .readthedocs.yml
Original file line number Diff line number Diff line change
@@ -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
Expand Down
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion README.rst
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@ Pycord is a modern, easy to use, feature-rich, and async ready API wrapper for D
Note
----

Pycord supports Python ``3.10`` - ``3.13``
Pycord supports Python ``3.10`` - ``3.14``

Key Features
------------
Expand Down
12 changes: 9 additions & 3 deletions discord/client.py
Original file line number Diff line number Diff line change
Expand Up @@ -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

Expand Down Expand Up @@ -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`]
Expand Down Expand Up @@ -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]]]] = (
{}
Expand Down
3 changes: 2 additions & 1 deletion discord/ext/commands/cooldowns.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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:
Expand Down
8 changes: 4 additions & 4 deletions discord/ext/tasks/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -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",)

Expand Down Expand Up @@ -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
Expand Down Expand Up @@ -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.
Expand Down
4 changes: 2 additions & 2 deletions discord/http.py
Original file line number Diff line number Diff line change
Expand Up @@ -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__)

Expand Down Expand Up @@ -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
Expand Down
4 changes: 2 additions & 2 deletions discord/ui/modal.py
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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(
Expand Down
18 changes: 18 additions & 0 deletions discord/utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -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()
12 changes: 7 additions & 5 deletions pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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 = [
Expand All @@ -24,6 +24,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",
Expand Down Expand Up @@ -84,7 +85,7 @@ test = [
[tool.setuptools_scm]

[tool.black]
target-version = ['py310', 'py311', 'py312', 'py313']
target-version = ['py310', 'py311', 'py312', 'py313', 'py314']

[tool.isort]
profile = "black"
Expand Down Expand Up @@ -125,15 +126,15 @@ asyncio_default_fixture_loop_scope = "function"

[tool.tox]
requires = ["tox>=4"]
env_list = ["3.13", "3.12", "3.11", "3.10", "3.13-novoice"]
env_list = ["3.14", "3.13", "3.12", "3.11", "3.10", "3.14-novoice"]

[tool.tox.env_run_base]
description = "run unit tests"
commands = [["pytest", { replace = "posargs", default = ["tests"], extend = true }]]
dependency_groups = ["test"]
extras = ["voice"]

[tool.tox.env."3.13-novoice"]
[tool.tox.env."3.14-novoice"]
description = "run import and warning tests without the voice extra"
commands = [[
"pytest",
Expand All @@ -144,7 +145,8 @@ extras = []

# GitHub actions
[tool.tox.gh.python]
"3.13" = ["3.13", "3.13-novoice"]
"3.14" = ["3.14", "3.14-novoice"]
"3.13" = ["3.13"]
"3.12" = ["3.12"]
"3.11" = ["3.11"]
"3.10" = ["3.10"]
Loading