From 3dfc3a383c6907153eb7be798b075eedf2fe8139 Mon Sep 17 00:00:00 2001 From: Spencer Brown Date: Thu, 5 Jan 2023 21:39:41 +1000 Subject: [PATCH] Add type annotations for `babel.messages` subpackage (#9455) --- stubs/babel/babel/messages/catalog.pyi | 178 +++++++++++++----------- stubs/babel/babel/messages/checkers.pyi | 10 +- stubs/babel/babel/messages/extract.pyi | 95 ++++++++++--- stubs/babel/babel/messages/jslexer.pyi | 37 ++--- stubs/babel/babel/messages/mofile.pyi | 8 +- stubs/babel/babel/messages/plurals.pyi | 10 +- stubs/babel/babel/messages/pofile.pyi | 84 ++++++----- 7 files changed, 260 insertions(+), 162 deletions(-) diff --git a/stubs/babel/babel/messages/catalog.pyi b/stubs/babel/babel/messages/catalog.pyi index e9a6a8adc..625bdd0e0 100644 --- a/stubs/babel/babel/messages/catalog.pyi +++ b/stubs/babel/babel/messages/catalog.pyi @@ -1,108 +1,126 @@ -from typing import Any +import datetime +from collections import OrderedDict +from collections.abc import Generator, Iterable, Iterator +from typing_extensions import TypeAlias + +from babel.core import Locale + +__all__ = ["Message", "Catalog", "TranslationError"] + +_MessageID: TypeAlias = str | tuple[str, ...] | list[str] class Message: - id: Any - string: Any - locations: Any - flags: Any - auto_comments: Any - user_comments: Any - previous_id: Any - lineno: Any - context: Any + id: _MessageID + string: _MessageID + locations: list[tuple[str, int]] + flags: set[str] + auto_comments: list[str] + user_comments: list[str] + previous_id: list[str] + lineno: int | None + context: str | None def __init__( self, - id, + id: str, string: str = ..., - locations=..., - flags=..., - auto_comments=..., - user_comments=..., - previous_id=..., - lineno: Any | None = ..., - context: Any | None = ..., + locations: Iterable[tuple[str, int]] = ..., + flags: Iterable[str] = ..., + auto_comments: Iterable[str] = ..., + user_comments: Iterable[str] = ..., + previous_id: _MessageID = ..., + lineno: int | None = ..., + context: str | None = ..., ) -> None: ... - def __cmp__(self, other): ... - def __gt__(self, other): ... - def __lt__(self, other): ... - def __ge__(self, other): ... - def __le__(self, other): ... - def __eq__(self, other): ... - def __ne__(self, other): ... + def __cmp__(self, other: Message) -> int: ... + def __gt__(self, other: Message) -> bool: ... + def __lt__(self, other: Message) -> bool: ... + def __ge__(self, other: Message) -> bool: ... + def __le__(self, other: Message) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... def is_identical(self, other: Message) -> bool: ... - def clone(self): ... - def check(self, catalog: Any | None = ...): ... + def clone(self) -> Message: ... + def check(self, catalog: Catalog | None = ...) -> list[TranslationError]: ... @property - def fuzzy(self): ... + def fuzzy(self) -> bool: ... @property - def pluralizable(self): ... + def pluralizable(self) -> bool: ... @property - def python_format(self): ... + def python_format(self) -> bool: ... class TranslationError(Exception): ... class Catalog: - domain: Any - locale: Any - project: Any - version: Any - copyright_holder: Any - msgid_bugs_address: Any - last_translator: Any - language_team: Any - charset: Any - creation_date: Any - revision_date: Any - fuzzy: Any - obsolete: Any + domain: str | None + project: str + version: str + copyright_holder: str + msgid_bugs_address: str + last_translator: str + language_team: str + charset: str + creation_date: datetime.datetime | str + revision_date: datetime.datetime | datetime.time | float | str + fuzzy: bool + obsolete: OrderedDict[str | tuple[str, str], Message] def __init__( self, - locale: Any | None = ..., - domain: Any | None = ..., - header_comment=..., - project: Any | None = ..., - version: Any | None = ..., - copyright_holder: Any | None = ..., - msgid_bugs_address: Any | None = ..., - creation_date: Any | None = ..., - revision_date: Any | None = ..., - last_translator: Any | None = ..., - language_team: Any | None = ..., - charset: Any | None = ..., + locale: str | Locale | None = ..., + domain: str | None = ..., + header_comment: str | None = ..., + project: str | None = ..., + version: str | None = ..., + copyright_holder: str | None = ..., + msgid_bugs_address: str | None = ..., + creation_date: datetime.datetime | str | None = ..., + revision_date: datetime.datetime | datetime.time | float | str | None = ..., + last_translator: str | None = ..., + language_team: str | None = ..., + charset: str | None = ..., fuzzy: bool = ..., ) -> None: ... @property - def locale_identifier(self): ... - header_comment: Any - mime_headers: Any + def locale(self) -> Locale | None: ... + @locale.setter # Assigning a string looks up the right Locale object. + def locale(self, value: Locale | str | None) -> None: ... @property - def num_plurals(self): ... + def locale_identifier(self) -> str | None: ... @property - def plural_expr(self): ... + def header_comment(self) -> str: ... + @header_comment.setter + def header_comment(self, value: str) -> None: ... @property - def plural_forms(self): ... - def __contains__(self, id): ... + def mime_headers(self) -> list[tuple[str, str]]: ... + @mime_headers.setter + def mime_headers(self, value: Iterable[tuple[str | bytes, str | bytes]]) -> None: ... + @property + def num_plurals(self) -> int: ... + @property + def plural_expr(self) -> str: ... + @property + def plural_forms(self) -> str: ... + def __contains__(self, id: _MessageID) -> bool: ... def __len__(self) -> int: ... - def __iter__(self): ... - def __delitem__(self, id) -> None: ... - def __getitem__(self, id): ... - def __setitem__(self, id, message) -> None: ... + def __iter__(self) -> Iterator[Message]: ... + def __delitem__(self, id: _MessageID) -> None: ... + def __getitem__(self, id: _MessageID) -> Message: ... + def __setitem__(self, id: _MessageID, message: Message) -> None: ... def add( self, - id, - string: Any | None = ..., - locations=..., - flags=..., - auto_comments=..., - user_comments=..., - previous_id=..., - lineno: Any | None = ..., - context: Any | None = ..., - ): ... - def check(self) -> None: ... - def get(self, id, context: Any | None = ...): ... - def delete(self, id, context: Any | None = ...) -> None: ... + id: _MessageID, + string: _MessageID | None = ..., + locations: Iterable[tuple[str, int]] = ..., + flags: Iterable[str] = ..., + auto_comments: Iterable[str] = ..., + user_comments: Iterable[str] = ..., + previous_id: _MessageID = ..., + lineno: int | None = ..., + context: str | None = ..., + ) -> Message: ... + def check(self) -> Generator[tuple[Message, list[TranslationError]], None, None]: ... + def get(self, id: _MessageID, context: str | None = ...): ... + def delete(self, id, context: str | None = ...) -> None: ... def update( - self, template, no_fuzzy_matching: bool = ..., update_header_comment: bool = ..., keep_user_comments: bool = ... + self, template: Catalog, no_fuzzy_matching: bool = ..., update_header_comment: bool = ..., keep_user_comments: bool = ... ) -> None: ... def is_identical(self, other: Catalog) -> bool: ... diff --git a/stubs/babel/babel/messages/checkers.pyi b/stubs/babel/babel/messages/checkers.pyi index 635794118..f115ecb3c 100644 --- a/stubs/babel/babel/messages/checkers.pyi +++ b/stubs/babel/babel/messages/checkers.pyi @@ -1,6 +1,8 @@ -from typing import Any +from collections.abc import Callable -def num_plurals(catalog, message) -> None: ... -def python_format(catalog, message) -> None: ... +from babel.messages.catalog import Catalog, Message -checkers: Any +def num_plurals(catalog: Catalog | None, message: Message) -> None: ... +def python_format(catalog: Catalog | None, message: Message) -> None: ... + +checkers: list[Callable[[Catalog | None, Message], object]] diff --git a/stubs/babel/babel/messages/extract.pyi b/stubs/babel/babel/messages/extract.pyi index 5e7127f56..ffc706c87 100644 --- a/stubs/babel/babel/messages/extract.pyi +++ b/stubs/babel/babel/messages/extract.pyi @@ -1,30 +1,85 @@ -from collections.abc import Callable -from typing import Any +from _typeshed import SupportsItems, SupportsRead, SupportsReadline +from collections.abc import Callable, Collection, Generator, Iterable, Mapping +from os import PathLike +from typing import Any, AnyStr, Protocol, overload +from typing_extensions import TypeAlias, TypedDict + +_Keyword: TypeAlias = tuple[int | tuple[int, int] | tuple[int, str], ...] | None GROUP_NAME: str -DEFAULT_KEYWORDS: Any -DEFAULT_MAPPING: Any +DEFAULT_KEYWORDS: dict[str, _Keyword] +DEFAULT_MAPPING: list[tuple[str, str]] empty_msgid_warning: str +@overload def extract_from_dir( - dirname: Any | None = ..., - method_map=..., - options_map: Any | None = ..., - keywords=..., - comment_tags=..., - callback: Any | None = ..., + dirname: AnyStr | PathLike[AnyStr], + method_map: Iterable[tuple[str, str]] = ..., + options_map: SupportsItems[str, dict[str, Any]] | None = ..., + keywords: Mapping[str, _Keyword] = ..., + comment_tags: Collection[str] = ..., + callback: Callable[[AnyStr, str, dict[str, Any]], object] | None = ..., strip_comment_tags: bool = ..., directory_filter: Callable[[str], bool] | None = ..., -) -> None: ... +) -> Generator[tuple[AnyStr, int, str | tuple[str, ...], list[str], str | None], None, None]: ... +@overload +def extract_from_dir( + dirname: None = ..., # No dirname causes os.getcwd() to be used, producing str. + method_map: Iterable[tuple[str, str]] = ..., + options_map: SupportsItems[str, dict[str, Any]] | None = ..., + keywords: Mapping[str, _Keyword] = ..., + comment_tags: Collection[str] = ..., + callback: Callable[[str, str, dict[str, Any]], object] | None = ..., + strip_comment_tags: bool = ..., + directory_filter: Callable[[str], bool] | None = ..., +) -> Generator[tuple[str, int, str | tuple[str, ...], list[str], str | None], None, None]: ... def check_and_call_extract_file( - filepath, method_map, options_map, callback, keywords, comment_tags, strip_comment_tags, dirpath: Any | None = ... -) -> None: ... + filepath: AnyStr | PathLike[AnyStr], + method_map: Iterable[tuple[str, str]], + options_map: SupportsItems[str, dict[str, Any]], + callback: Callable[[AnyStr, str, dict[str, Any]], object] | None, + keywords: Mapping[str, _Keyword], + comment_tags: Collection[str], + strip_comment_tags, + dirpath: Any | None = ..., +) -> Generator[tuple[AnyStr, int, str | tuple[str, ...], list[str], str | None], None, None]: ... def extract_from_file( - method, filename, keywords=..., comment_tags=..., options: Any | None = ..., strip_comment_tags: bool = ... -): ... + method, + filename: AnyStr | PathLike[AnyStr], + keywords: Mapping[str, _Keyword] = ..., + comment_tags: Collection[str] = ..., + options: dict[str, Any] | None = ..., + strip_comment_tags: bool = ..., +) -> list[tuple[AnyStr, int, str | tuple[str, ...], list[str], str | None]]: ... + +class _FileObj(SupportsRead[bytes], SupportsReadline[bytes], Protocol): + def seek(self, __offset: int, __whence: int = ...) -> int: ... + def tell(self) -> int: ... + def extract( - method, fileobj, keywords=..., comment_tags=..., options: Any | None = ..., strip_comment_tags: bool = ... -) -> None: ... -def extract_nothing(fileobj, keywords, comment_tags, options): ... -def extract_python(fileobj, keywords, comment_tags, options): ... -def extract_javascript(fileobj, keywords, comment_tags, options) -> None: ... + method, + fileobj: _FileObj, + keywords: Mapping[str, _Keyword] = ..., + comment_tags: Collection[str] = ..., + options: dict[str, Any] | None = ..., + strip_comment_tags: bool = ..., +) -> Iterable[tuple[int, str | tuple[str, ...], list[str], str | None]]: ... +def extract_nothing( + fileobj: _FileObj, keywords: Mapping[str, _Keyword], comment_tags: Collection[str], options: dict[str, Any] +) -> Iterable[tuple[int, str | tuple[str, ...], list[str], str | None]]: ... + +class _PyOptions(TypedDict, total=False): + encoding: str + +def extract_python( + fileobj: _FileObj, keywords: Mapping[str, _Keyword], comment_tags: Collection[str], options: _PyOptions +) -> Iterable[tuple[int, str | tuple[str, ...], list[str], str | None]]: ... + +class _JSOptions(TypedDict, total=False): + encoding: str + jsx: bool + template_string: bool + +def extract_javascript( + fileobj: _FileObj, keywords: Mapping[str, _Keyword], comment_tags: Collection[str], options: _JSOptions +) -> Iterable[tuple[int, str | tuple[str, ...], list[str], str | None]]: ... diff --git a/stubs/babel/babel/messages/jslexer.pyi b/stubs/babel/babel/messages/jslexer.pyi index b08766d69..6eb487394 100644 --- a/stubs/babel/babel/messages/jslexer.pyi +++ b/stubs/babel/babel/messages/jslexer.pyi @@ -1,21 +1,24 @@ -from typing import Any, NamedTuple +from collections.abc import Generator, Sequence +from re import Pattern +from typing import NamedTuple -operators: Any -escapes: Any -name_re: Any -dotted_name_re: Any -division_re: Any -regex_re: Any -line_re: Any -line_join_re: Any -uni_escape_re: Any +operators: Sequence[str] +escapes: dict[str, str] +name_re: Pattern[str] +dotted_name_re: Pattern[str] +division_re: Pattern[str] +regex_re: Pattern[str] +line_re: Pattern[str] +line_join_re: Pattern[str] +uni_escape_re: Pattern[str] class Token(NamedTuple): - type: Any - value: Any - lineno: Any + type: str + value: str + lineno: int -def get_rules(jsx, dotted, template_string): ... -def indicates_division(token): ... -def unquote_string(string): ... -def tokenize(source, jsx: bool = ..., dotted: bool = ..., template_string: bool = ...) -> None: ... +# Documented as private +def get_rules(jsx: bool, dotted: bool, template_string: bool) -> list[tuple[str | None, Pattern[str]]]: ... # undocumented +def indicates_division(token: Token) -> bool: ... +def unquote_string(string: str) -> str: ... +def tokenize(source: str, jsx: bool = ..., dotted: bool = ..., template_string: bool = ...) -> Generator[Token, None, None]: ... diff --git a/stubs/babel/babel/messages/mofile.pyi b/stubs/babel/babel/messages/mofile.pyi index a7e7362a5..df15e4efd 100644 --- a/stubs/babel/babel/messages/mofile.pyi +++ b/stubs/babel/babel/messages/mofile.pyi @@ -1,5 +1,9 @@ +from _typeshed import SupportsRead, SupportsWrite + +from babel.messages.catalog import Catalog + LE_MAGIC: int BE_MAGIC: int -def read_mo(fileobj): ... -def write_mo(fileobj, catalog, use_fuzzy: bool = ...) -> None: ... +def read_mo(fileobj: SupportsRead[bytes]) -> Catalog: ... +def write_mo(fileobj: SupportsWrite[bytes], catalog: Catalog, use_fuzzy: bool = ...) -> None: ... diff --git a/stubs/babel/babel/messages/plurals.pyi b/stubs/babel/babel/messages/plurals.pyi index 9f87c986a..2d6ea9c76 100644 --- a/stubs/babel/babel/messages/plurals.pyi +++ b/stubs/babel/babel/messages/plurals.pyi @@ -1,8 +1,6 @@ -from typing import Any - -LC_CTYPE: Any -PLURALS: Any -DEFAULT_PLURAL: Any +LC_CTYPE: str +PLURALS: dict[str, tuple[int, str]] +DEFAULT_PLURAL: tuple[int, str] class _PluralTuple(tuple[int, str]): @property @@ -12,4 +10,4 @@ class _PluralTuple(tuple[int, str]): @property def plural_forms(self) -> str: ... -def get_plural(locale=...): ... +def get_plural(locale: str = ...) -> _PluralTuple: ... diff --git a/stubs/babel/babel/messages/pofile.pyi b/stubs/babel/babel/messages/pofile.pyi index 6fdccac1c..b349dc4bd 100644 --- a/stubs/babel/babel/messages/pofile.pyi +++ b/stubs/babel/babel/messages/pofile.pyi @@ -1,53 +1,71 @@ -from typing import Any +from _typeshed import SupportsWrite +from collections.abc import Iterable +from re import Pattern -def unescape(string): ... -def denormalize(string): ... +from babel.core import Locale +from babel.messages.catalog import Catalog + +def unescape(string: str) -> str: ... +def denormalize(string: str) -> str: ... class PoFileError(Exception): - catalog: Any - line: Any - lineno: Any - def __init__(self, message, catalog, line, lineno) -> None: ... + catalog: Catalog + line: str + lineno: int + def __init__(self, message: str, catalog: Catalog, line: str, lineno: int) -> None: ... class _NormalizedString: - def __init__(self, *args) -> None: ... - def append(self, s) -> None: ... - def denormalize(self): ... + def __init__(self, *args: str) -> None: ... + def append(self, s: str) -> None: ... + def denormalize(self) -> str: ... def __bool__(self) -> bool: ... - def __cmp__(self, other): ... - def __gt__(self, other): ... - def __lt__(self, other): ... - def __ge__(self, other): ... - def __le__(self, other): ... - def __eq__(self, other): ... - def __ne__(self, other): ... + def __cmp__(self, other: object) -> int: ... + def __gt__(self, other: object) -> bool: ... + def __lt__(self, other: object) -> bool: ... + def __ge__(self, other: object) -> bool: ... + def __le__(self, other: object) -> bool: ... + def __eq__(self, other: object) -> bool: ... + def __ne__(self, other: object) -> bool: ... class PoFileParser: - catalog: Any - ignore_obsolete: Any + catalog: Catalog + ignore_obsolete: bool counter: int offset: int - abort_invalid: Any + abort_invalid: bool + # Internal variables: + messages: list[_NormalizedString] + # [index, string] lists + translations: list[list[int | _NormalizedString]] + locations: list[tuple[str, int | None]] + flags: list[str] + user_comments: list[str] + auto_comments: list[str] + context: str | None + obsolete: bool + in_msgid: bool + in_msgstr: bool + in_msgctxt: bool def __init__(self, catalog, ignore_obsolete: bool = ..., abort_invalid: bool = ...) -> None: ... - def parse(self, fileobj) -> None: ... + def parse(self, fileobj: Iterable[str | bytes]) -> None: ... def read_po( - fileobj, - locale: Any | None = ..., - domain: Any | None = ..., + fileobj: Iterable[str | bytes], + locale: str | Locale | None = ..., + domain: str | None = ..., ignore_obsolete: bool = ..., - charset: Any | None = ..., + charset: str | None = ..., abort_invalid: bool = ..., -): ... +) -> Catalog: ... -WORD_SEP: Any +WORD_SEP: Pattern[str] -def escape(string): ... -def normalize(string, prefix: str = ..., width: int = ...): ... +def escape(string: str) -> str: ... +def normalize(string: str, prefix: str = ..., width: int = ...) -> str: ... def write_po( - fileobj, - catalog, - width: int = ..., + fileobj: SupportsWrite[bytes], + catalog: Catalog, + width: int | None = ..., no_location: bool = ..., omit_header: bool = ..., sort_output: bool = ..., @@ -55,4 +73,4 @@ def write_po( ignore_obsolete: bool = ..., include_previous: bool = ..., include_lineno: bool = ..., -): ... +) -> None: ...