diff --git a/util/locale_database/cldr.py b/util/locale_database/cldr.py index 450d868bfc6..6ed1d7a7793 100644 --- a/util/locale_database/cldr.py +++ b/util/locale_database/cldr.py @@ -21,7 +21,8 @@ from localetools import names_clash from qlocalexml import Locale class CldrReader (object): - def __init__(self, root: Path, grumble = lambda msg: None, whitter = lambda msg: None): + def __init__(self, root: Path, grumble: Callable[[str], int] = lambda msg: 0, + whitter: Callable[[str], int] = lambda msg: 0) -> None: """Set up a reader object for reading CLDR data. Single parameter, root, is the file-system path to the root of @@ -38,9 +39,10 @@ class CldrReader (object): self.whitter, self.grumble = whitter, grumble self.root.checkEnumData(grumble) # TODO: can we do anything but ignore with the namings here ? - self.__bcp47Alias, ignore = self.root.bcp47Aliases() + self.__bcp47Alias, _ = self.root.bcp47Aliases() - def likelySubTags(self): + def likelySubTags(self) -> Iterator[tuple[tuple[int, int, int, int], + tuple[int, int, int, int]]]: """Generator for likely subtag information. Yields pairs (have, give) of 4-tuples; if what you have @@ -51,8 +53,8 @@ class CldrReader (object): skips = [] for got, use in self.root.likelySubTags(): try: - have = self.__parseTags(got) - give = self.__parseTags(use) + have: tuple[int, int, int, int] = self.__parseTags(got) + give: tuple[int, int, int, int] = self.__parseTags(use) except Error as e: if ((use.startswith(got) or got.startswith('und_')) and e.message.startswith('Unknown ') and ' code ' in e.message): @@ -77,7 +79,12 @@ class CldrReader (object): # more out. pass # self.__wrapped(self.whitter, 'Skipping likelySubtags (for unknown codes): ', skips) - def zoneData(self): + def zoneData(self) -> tuple[dict[str, str], + dict[str, str], + dict[tuple[str, str], str], + dict[str, dict[str, str]], + dict[str, tuple[tuple[int, int, str], ...]], + dict[str, str]]: """Locale-independent timezone data. Returns a tuple (alias, defaults, winIds, metamap, zones, @@ -107,12 +114,15 @@ class CldrReader (object): that are not mentioned in enumdata.territory_map, on any Windows IDs given in zonedata.windowsIdList that are no longer covered by the CLDR data.""" - alias = self.__bcp47Alias + alias: dict[str, str] = self.__bcp47Alias + # defaults is a dict[str, str] and winIds is a list[tuple[str, str, str]] defaults, winIds = self.root.readWindowsTimeZones(alias) + # metamap is a dict[str, dict[str, str]], + # zones is dict[str, tuple[tuple[int, int, str], ...]], territorial is a dict[str, str] metamap, zones, territorial = self.root.readMetaZoneMap(alias) from zonedata import windowsIdList - winUnused = set(n for n, o in windowsIdList).difference( + winUnused: set[str] = set(n for n, o in windowsIdList).difference( set(defaults).union(w for w, t, ids in winIds)) if winUnused: joined = "\n\t".join(winUnused) @@ -122,7 +132,7 @@ class CldrReader (object): # Check for duplicate entries in winIds: last: tuple[str, str, str] = ('', '', '') - winDup = {} + winDup: dict[tuple[str, str], list[str]] = {} for triple in sorted(winIds): if triple[:2] == last[:2]: winDup.setdefault(triple[:2], []).append(triple[-1]) @@ -142,7 +152,7 @@ class CldrReader (object): winIds.append((w, t, ' '.join(ianaList))) from enumdata import territory_map - unLand = set(t for w, t, ids in winIds).union(territorial) + unLand: set[str] = set(t for w, t, ids in winIds).union(territorial) for bok in metamap.values(): unLand = unLand.union(bok) unLand = unLand.difference(v[1] for k, v in territory_map.items()) @@ -154,16 +164,17 @@ class CldrReader (object): winIds = [(w, t, ids) for w, t, ids in winIds if t not in unLand] # Convert list of triples to mapping: - winIds = {(w, t): ids for w, t, ids in winIds} + winIds: dict[tuple[str, str], str] = {(w, t): ids for w, t, ids in winIds} return alias, defaults, winIds, metamap, zones, territorial - def readLocales(self, calendars = ('gregorian',)): + def readLocales(self, calendars: Iterable[str] = ('gregorian',) + ) -> dict[tuple[int, int, int, int], Locale]: return {(k.language_id, k.script_id, k.territory_id, k.variant_id): k for k in self.__allLocales(calendars)} - def __allLocales(self, calendars): - def skip(locale, reason): + def __allLocales(self, calendars: list[str]) -> Iterator[Locale]: + def skip(locale: str, reason: str) -> str: return f'Skipping defaultContent locale "{locale}" ({reason})\n' for locale in self.root.defaultContentLocales: @@ -205,14 +216,14 @@ class CldrReader (object): import textwrap @staticmethod - def __wrapped(writer, prefix, tokens, wrap = textwrap.wrap): + def __wrapped(writer, prefix, tokens, wrap = textwrap.wrap) -> None: writer('\n'.join(wrap(prefix + ', '.join(tokens), subsequent_indent=' ', width=80)) + '\n') del textwrap - def __parseTags(self, locale): - tags = self.__splitLocale(locale) - language = next(tags) + def __parseTags(self, locale: str) -> tuple[int, int, int, int]: + tags: Iterator[str] = self.__splitLocale(locale) + language: str = next(tags) script = territory = variant = '' try: script, territory, variant = tags @@ -220,7 +231,7 @@ class CldrReader (object): pass return tuple(p[0] for p in self.root.codesToIdName(language, script, territory, variant)) - def __splitLocale(self, name): + def __splitLocale(self, name: str) -> Iterator[str]: """Generate (language, script, territory, variant) from a locale name Ignores any trailing fields (with a warning), leaves script (a @@ -229,11 +240,11 @@ class CldrReader (object): empty if unspecified. Only generates one entry if name is a single tag (i.e. contains no underscores). Always yields 1 or 4 values, never 2 or 3.""" - tags = iter(name.split('_')) + tags: Iterator[str] = iter(name.split('_')) yield next(tags) # Language try: - tag = next(tags) + tag: str = next(tags) except StopIteration: return @@ -270,7 +281,8 @@ class CldrReader (object): if rest: self.grumble(f'Ignoring unparsed cruft {"_".join(rest)} in {name}\n') - def __getLocaleData(self, scan, calendars, language, script, territory, variant): + def __getLocaleData(self, scan: LocaleScanner, calendars: list[str], language: str, + script: str, territory: str, variant: str) -> Locale: ids, names = zip(*self.root.codesToIdName(language, script, territory, variant)) assert ids[0] > 0 and ids[2] > 0, (language, script, territory, variant) locale = Locale( diff --git a/util/locale_database/cldr2qlocalexml.py b/util/locale_database/cldr2qlocalexml.py index f13a77c601c..d4ba6960517 100755 --- a/util/locale_database/cldr2qlocalexml.py +++ b/util/locale_database/cldr2qlocalexml.py @@ -38,10 +38,11 @@ from pathlib import Path import argparse from cldr import CldrReader +from typing import TextIO from qlocalexml import QLocaleXmlWriter -def main(argv, out, err): +def main(argv: list[str], out: TextIO, err: TextIO) -> int: """Generate a QLocaleXML file from CLDR data. Takes sys.argv, sys.stdout, sys.stderr (or equivalents) as @@ -87,7 +88,7 @@ def main(argv, out, err): parser.error(f'Failed to open "{xml}" to write output to it') reader = CldrReader(root, - (lambda *x: None) if args.verbose < 0 else + (lambda *x: 0) if args.verbose < 0 else # Use stderr for logging if stdout is where our XML is going: err.write if out is emit else out.write, err.write)