interactions.py icon indicating copy to clipboard operation
interactions.py copied to clipboard

[FEAT] Upgrade support and refactor with Python 3.11–3.14 features

Open kazuki-tetsuya opened this issue 6 months ago • 5 comments

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 using asyncio.TaskGroup (PEP 654) and handle failures using ExceptionGroup. Target: http_client.py:418–422
  • Replace asyncio.wait_for() with asyncio.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 tomli with built-in tomllib. Target: setup.py:7–8, pyproject.toml:1–4, 13
  • Refactor type hints using Self, NotRequired, Required in TypedDict, 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 Unpack to type **kwargs. Target: message.py:1017–1040
  • Add @typing.override decorators to overridden methods. Target: context.py:841–845
  • Use asyncio.eager_task_factory(), asyncio.create_eager_task_factory(), and asyncio.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() and PythonFinalizationError. Target: gateway.py:117-127, 110–135
  • Use TypeIs in polymorphic typing contexts. Target: client.py:1841–1855
  • Adopt PEP 696 type parameter defaults. Target: context.py:420–422
  • Add support for warnings.deprecated() and typing.ReadOnly in API response models
  • Use ssl.create_default_context(). Target: http_client.py:12–14 (depending on aiohttp’s handling)
  • Future-proof functools.partial usage by wrapping in staticmethod as its behavior changes in future versions. Target: client.py:3

Python 3.14

  • Use InterpreterPoolExecutor to offload CPU-intensive tasks in extensions, replacing thread pools or uvloop where 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 Union types (Union[A, B] and A | 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.

kazuki-tetsuya avatar May 13 '25 08:05 kazuki-tetsuya

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

silasary avatar May 13 '25 09:05 silasary

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.

ghost avatar May 13 '25 09:05 ghost

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.

AstreaTSS avatar May 13 '25 11:05 AstreaTSS

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.

mifuyutsuki avatar May 13 '25 11:05 mifuyutsuki

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.

ghost avatar May 13 '25 15:05 ghost