DeepLcom / deepl-python

Official Python library for the DeepL language translation API.
MIT License
1.06k stars 75 forks source link

translated_text should use method overload to have better typing #84

Open DanieleIsoni opened 7 months ago

DanieleIsoni commented 7 months ago

In the typing of the translate_text it would be better to use method overloading, so that the return type is not ambiguous when passing a text variable that is either str or Iterable[str]

So I suggest that here https://github.com/DeepLcom/deepl-python/blob/16108b0b4b196a67e8d5168490098dd96b312efe/deepl/translator.py#L334-L350 the typing should be something like:

@overload
def translate_text(
        self,
        text: str,
        *,
        source_lang: Union[str, Language, None] = None,
        target_lang: Union[str, Language],
        context: Optional[str] = None,
        split_sentences: Union[str, SplitSentences, None] = None,
        preserve_formatting: Optional[bool] = None,
        formality: Union[str, Formality, None] = None,
        glossary: Union[str, GlossaryInfo, None] = None,
        tag_handling: Optional[str] = None,
        outline_detection: Optional[bool] = None,
        non_splitting_tags: Union[str, List[str], None] = None,
        splitting_tags: Union[str, List[str], None] = None,
        ignore_tags: Union[str, List[str], None] = None,
    ) -> TextResult:
    ...

@overload
def translate_text(
        self,
        text: Iterable[str],
        *,
        source_lang: Union[str, Language, None] = None,
        target_lang: Union[str, Language],
        context: Optional[str] = None,
        split_sentences: Union[str, SplitSentences, None] = None,
        preserve_formatting: Optional[bool] = None,
        formality: Union[str, Formality, None] = None,
        glossary: Union[str, GlossaryInfo, None] = None,
        tag_handling: Optional[str] = None,
        outline_detection: Optional[bool] = None,
        non_splitting_tags: Union[str, List[str], None] = None,
        splitting_tags: Union[str, List[str], None] = None,
        ignore_tags: Union[str, List[str], None] = None,
    ) -> List[TextResult]:
    ...

def translate_text(
        self,
        text: Union[str, Iterable[str]],
        *,
        source_lang: Union[str, Language, None] = None,
        target_lang: Union[str, Language],
        context: Optional[str] = None,
        split_sentences: Union[str, SplitSentences, None] = None,
        preserve_formatting: Optional[bool] = None,
        formality: Union[str, Formality, None] = None,
        glossary: Union[str, GlossaryInfo, None] = None,
        tag_handling: Optional[str] = None,
        outline_detection: Optional[bool] = None,
        non_splitting_tags: Union[str, List[str], None] = None,
        splitting_tags: Union[str, List[str], None] = None,
        ignore_tags: Union[str, List[str], None] = None,
    ) -> Union[TextResult, List[TextResult]]:

If typed like this mypy understands that when text is a str the return type is TextResult and when it is an Iterable[str] the return type is List[TextResult], avoiding error messages like when passing an Iterable[str] as text:

<file>:102: error: Item "TextResult" of "TextResult | list[TextResult]" has no attribute "__iter__" (not iterable)  [union-attr]

If you prefer, I'd be glad submit a pull request

JanEbbing commented 7 months ago

This is a great suggestion, if you could up a PR I'll merge it, thanks!