interactions.py
interactions.py copied to clipboard
[FEAT] Upgrade support and refactor with Python 3.11–3.14 features
Problem Description
The library currently targets Python 3.10 and 3.11, but misses opportunities to leverage new features from newer versions (3.12 to 3.14). As Python evolves, many areas of this codebase can be improved.
Proposed Solution
Refactor, migrate and modernize the code incrementally to take advantage of features introduced in Python 3.11–3.14:
Python 3.11
- Replace
asyncio.gather()with manual error handling usingasyncio.TaskGroup(PEP 654) and handle failures usingExceptionGroup. Target:http_client.py:418–422 - Replace
asyncio.wait_for()withasyncio.timeout(). Target:client.py:1638,client.py:2042 - Replace string-based enums with
StrEnum. Target:enums.py:703–747,application_commands.py:137–150 - Replace
tomliwith built-intomllib. Target:setup.py:7–8,pyproject.toml:1–4, 13 - Refactor type hints using
Self,NotRequired,RequiredinTypedDict, parameterized generics. Target:user.py:2,application_commands.py:168
Python 3.12
- Use PEP 695 syntax for declaring type parameters and aliases. Target:
context.py:420–421,user.pyi:37–39 - Use
Unpackto type**kwargs. Target:message.py:1017–1040 - Add
@typing.overridedecorators to overridden methods. Target:context.py:841–845 - Use
asyncio.eager_task_factory(),asyncio.create_eager_task_factory(), andasyncio.current_task()in latency-critical sections. Target:http_client.py:414–415,client.py:1944–1950 - Use
itertools.batched()for layout grouping and pagination logic. Target:components.py:822–840,paginators.py:348–364
Python 3.13
- Evaluate impact of free-threading (PEP 703) and JIT compilation (PEP 744) on WebSocket/API, especially in:
client.py:1840–1847,GatewayClient, context resolution. - Use
copy.replace()for immutable model transformation. Target:__init__.py:121–178 - Use
asyncio.Queue.shutdown(),asyncio.as_completed()andPythonFinalizationError. Target:gateway.py:117-127, 110–135 - Use
TypeIsin polymorphic typing contexts. Target:client.py:1841–1855 - Adopt PEP 696 type parameter defaults. Target:
context.py:420–422 - Add support for
warnings.deprecated()andtyping.ReadOnlyin API response models - Use
ssl.create_default_context(). Target:http_client.py:12–14(depending on aiohttp’s handling) - Future-proof
functools.partialusage by wrapping instaticmethodas its behavior changes in future versions. Target:client.py:3
Python 3.14
- Use
InterpreterPoolExecutorto offload CPU-intensive tasks in extensions, replacing thread pools oruvloopwhere applicable. Target:client.py:1001–1016 - Refactor forward references using PEP 649 & 749 to allow runtime evaluation of annotations. Target:
client.py:371–381 - Unify
Uniontypes (Union[A, B]andA | B) - Adopt PEP 750 t-strings. Target:
client.py:325–337
Alternatives Considered
No response
Additional Information
These enhancements can be rolled out incrementally.
As the Discord API evolves and bots handle more concurrency and CPU-bound work, leveraging these language improvements will be increasingly beneficial.
Code of Conduct
- [x] I agree to follow the contribution requirements.
Right now, I'm not comfortable with pushing our minimum beyond 3.12, but I absolutely agree that we should be using 3.11 and 3.12 features
Right now, I'm not comfortable with pushing our minimum beyond 3.12, but I absolutely agree that we should be using 3.11 and 3.12 features
Thanks for the feedback, that makes perfect sense. Targeting 3.11 and 3.12 sounds good, and we can defer 3.13+ features until the minimum version policy evolves. While I completely respect your decision, I personally lean toward using the second-latest stable version as the minimum for major releases, as it tends to strike a solid balance between stability and access to modern features. Given that 6.0 is a major release, would it make sense to align these improvements with it? It seems like a natural point to modernize the internals while setting 3.12 as the baseline.
I will note that minimum versions are less about stability (in my eyes) than they are adoption - too new of a version means we lose out on a number of people. I'd argue part of the reason we have stayed with 3.10 for so long is because it has become a widely adopted version, which is convenient for everyone involved. That being said, upgrading now makes sense as 3.10 slowly becomes less and less used.
6.0 would be the time to upgrade and make this sort of breaking change, yes. Although I'm unsure when 6.0 will be 😅 we've all been busy.
The oldest supported Python version is 3.10 (which is supported until Oct 2026), per the library's pre-commit and CI settings. If we want widest Python compatibility, we should not be using features beyond the minimum version. I haven't seen much urgency yet as to use the newer features, apart from refactoring out deprecated features.
I will note that minimum versions are less about stability (in my eyes) than they are adoption - too new of a version means we lose out on a number of people. I'd argue part of the reason we have stayed with 3.10 for so long is because it has become a widely adopted version, which is convenient for everyone involved. That being said, upgrading now makes sense as 3.10 slowly becomes less and less used.
6.0 would be the time to upgrade and make this sort of breaking change, yes. Although I'm unsure when 6.0 will be 😅 we've all been busy.
The oldest supported Python version is 3.10 (which is supported until Oct 2026), per the library's pre-commit and CI settings. If we want widest Python compatibility, we should not be using features beyond the minimum version. I haven't seen much urgency yet as to use the newer features, apart from refactoring out deprecated features.
Thanks both for the thoughtful replies. I don’t mean to suggest we drop support for 3.10 prematurely. My main intent with this issue is to begin preparing for 6.0, by gradually using modern language features (within the agreed-upon minimum), even if these aren’t strictly urgent. Things are not just nice-to-haves but tools that help make the lib more expressive in the long run. Also, I’d be happy to help however I can, whether through refactoring, tests, or triaging what makes sense to modernize incrementally.