Add type annotations to CldrReader

Add some type annotatons to cldr2qlocalexml.py as well. Based on the
default arguments the constructor of CldrReader was expecting callables
that return None, but in reality we are passing in functions that
return integers.

Task-number: QTBUG-129613
Pick-to: 6.8
Change-Id: I06832240956ea635ca0cc0ec45c466a3b2539ff7
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Mate Barany 2024-10-14 17:01:29 +02:00
parent 96b9c4c317
commit 812f79e75f
2 changed files with 37 additions and 24 deletions

View File

@ -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(

View File

@ -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)