Skip to content

Commit 7aeb842

Browse files
committed
Add Generic to Translator and add translator property to Context
1 parent 245a3b8 commit 7aeb842

File tree

3 files changed

+33
-19
lines changed

3 files changed

+33
-19
lines changed

twitchio/ext/commands/context.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,15 @@ def type(self) -> ContextType:
256256
"""
257257
return self._type
258258

259+
@property
260+
def translator(self) -> Translator[Any] | None:
261+
"""Property returning the :class:`.commands.Translator` assigned to the :class:`.commands.Command` if found or
262+
``None``. This property will always return ``None`` if no valid command or prefix is associated with this Context."""
263+
if not self.command:
264+
return None
265+
266+
return self.command.translator
267+
259268
@property
260269
def error_dispatched(self) -> bool:
261270
return self._error_dispatched
@@ -594,7 +603,7 @@ async def send_translated(self, content: str, *, me: bool = False, langcode: str
594603
TranslatorError
595604
An error occurred during translation.
596605
"""
597-
translator: Translator | None = getattr(self.command, "translator", None)
606+
translator: Translator[Any] | None = self.translator
598607
new = (f"/me {content}" if me else content).strip()
599608

600609
if not self.command or not translator:
@@ -722,7 +731,7 @@ async def reply_translated(self, content: str, *, me: bool = False, langcode: st
722731
if self._type is ContextType.REWARD:
723732
raise TypeError("Cannot reply to a message in a Reward based context.")
724733

725-
translator: Translator | None = getattr(self.command, "translator", None)
734+
translator: Translator[Any] | None = self.translator
726735
new = (f"/me {content}" if me else content).strip()
727736

728737
if not self.command or not translator:

twitchio/ext/commands/core.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -225,11 +225,11 @@ def __init__(
225225
self._before_hook: Callable[[Component_T, Context[Any]], Coro] | Callable[[Context[Any]], Coro] | None = None
226226
self._after_hook: Callable[[Component_T, Context[Any]], Coro] | Callable[[Context[Any]], Coro] | None = None
227227

228-
translator: Translator | type[Translator] | None = getattr(callback, "__command_translator__", None)
228+
translator: Translator[Any] | type[Translator[Any]] | None = getattr(callback, "__command_translator__", None)
229229
if translator and inspect.isclass(translator):
230230
translator = translator()
231231

232-
self._translator: Translator | None = translator
232+
self._translator: Translator[Any] | None = translator
233233

234234
self._help: str = callback.__doc__ or ""
235235
self.__doc__ = self._help
@@ -271,7 +271,7 @@ def _get_signature(self) -> None:
271271
self._signature = help_sig
272272

273273
@property
274-
def translator(self) -> Translator | None:
274+
def translator(self) -> Translator[Any] | None:
275275
"""Property returning the :class:`.commands.Translator` associated with this command or ``None`` if one was not
276276
used.
277277
"""
@@ -1482,7 +1482,7 @@ def wrapper(
14821482
return wrapper
14831483

14841484

1485-
def translator(cls: Translator | type[Translator]) -> Any:
1485+
def translator(cls: Translator[Any] | type[Translator[Any]]) -> Any:
14861486
"""|deco|
14871487
14881488
Decorator which adds a :class:`.commands.Translator` to a :class:`.commands.Command`.

twitchio/ext/commands/translators.py

Lines changed: 18 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -25,17 +25,20 @@
2525
from __future__ import annotations
2626

2727
import abc
28-
from typing import TYPE_CHECKING, Any
28+
from typing import TYPE_CHECKING, Any, Generic, TypeVar
2929

3030

3131
if TYPE_CHECKING:
3232
from .context import Context
3333

3434

35+
T = TypeVar("T")
36+
37+
3538
__all__ = ("Translator",)
3639

3740

38-
class Translator(abc.ABC):
41+
class Translator(Generic[T], abc.ABC):
3942
"""Abstract Base Class for command translators.
4043
4144
This class allows you to implement logic to translate messages sent via the :meth:`.commands.Context.send_translated`
@@ -49,16 +52,16 @@ class Translator(abc.ABC):
4952
"""
5053

5154
@abc.abstractmethod
52-
def get_langcode(self, ctx: Context[Any], name: str) -> str | None:
55+
def get_langcode(self, ctx: Context[Any], name: str) -> T | None:
5356
"""Method which is called when :meth:`.commands.Context.send_translated` is used on a :class:`.commands.Command`
5457
which has an associated Translator, to determine the ``langcode`` which should be passed to :meth:`.translate` or ``None``
5558
if the content should not be translated.
5659
57-
By default the ``name`` or ``alias`` used to invoke the command is passed alongside :class:`.commands.Context` to aid in
58-
determining the ``langcode`` you should use.
60+
By default the lowercase ``name`` or ``alias`` used to invoke the command is passed alongside :class:`.commands.Context`
61+
to aid in determining the ``langcode`` you should use.
5962
60-
You can use any system for the language codes, however they must be a :class:`str`. We also recommend using a
61-
recognized system such as the ``ISO 639`` language code format.
63+
You can use any format or type for the language codes. We recommend using a recognized system such as the ``ISO 639``
64+
language code format as a :class:`str`.
6265
6366
Parameters
6467
----------
@@ -70,8 +73,10 @@ def get_langcode(self, ctx: Context[Any], name: str) -> str | None:
7073
7174
Returns
7275
-------
73-
str
74-
The language code as a :class:`str` to pass to :meth:`.translate`.
76+
Any
77+
The language code to pass to :meth:`.translate`.
78+
None
79+
No translation attempt should be made with :meth:`.translate`.
7580
7681
Example
7782
-------
@@ -81,7 +86,7 @@ def get_langcode(self, ctx: Context[Any], name: str) -> str | None:
8186
# For example purposes only the "get_langcode" method is shown in this example...
8287
# The "translate" method must also be implemented...
8388
84-
class HelloTranslator(commands.Translator):
89+
class HelloTranslator(commands.Translator[str]):
8590
def __init__(self) -> None:
8691
self.code_mapping = {"hello": "en", "bonjour": "fr"}
8792
@@ -98,7 +103,7 @@ async def hello_command(ctx: commands.Context) -> None:
98103
"""
99104

100105
@abc.abstractmethod
101-
async def translate(self, ctx: Context[Any], text: str, langcode: str) -> str:
106+
async def translate(self, ctx: Context[Any], text: str, langcode: T) -> str:
102107
"""|coro|
103108
104109
Method used to translate the content passed to :meth:`.commands.Context.send_translated` with the language code returned from
@@ -116,7 +121,7 @@ async def translate(self, ctx: Context[Any], text: str, langcode: str) -> str:
116121
The context surrounding the command invocation.
117122
text: str
118123
The content passed to :meth:`~.commands.Context.send_translated` which should be translated.
119-
langcode: str
124+
langcode: Any
120125
The language code returned via :meth:`.get_langcode`, which can be used to determine the language the text should
121126
be translated to.
122127
@@ -133,7 +138,7 @@ async def translate(self, ctx: Context[Any], text: str, langcode: str) -> str:
133138
# For example purposes only the "translate" method is shown in this example...
134139
# The "get_langcode" method must also be implemented...
135140
136-
class HelloTranslator(commands.Translator):
141+
class HelloTranslator(commands.Translator[str]):
137142
138143
async def translate(self, ctx: commands.Context, text: str, langcode: str) -> str:
139144
# Usually you would call an API, or retrieve from a database or dict or some other solution...

0 commit comments

Comments
 (0)