Add type annotations to QLocaleXmlReader

Task-number: QTBUG-129564
Change-Id: I8711152840e6bcb39ff1b1e67ff60b53801f28f0
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
(cherry picked from commit feb39b2d033eae19937e86eca89c1c96141a0b4f)
This commit is contained in:
Mate Barany 2024-10-15 17:12:25 +02:00
parent 42e138a529
commit 8c0867699c

View File

@ -19,8 +19,9 @@ You can download jing from https://relaxng.org/jclark/jing.html if your
package manager lacks the jing package. package manager lacks the jing package.
""" """
from typing import Iterator from typing import Callable, Iterable, Iterator
from xml.sax.saxutils import escape from xml.sax.saxutils import escape
from xml.dom import minidom
from localetools import Error from localetools import Error
@ -46,14 +47,16 @@ def startCount(c, text): # strspn
return len(text) return len(text)
class QLocaleXmlReader (object): class QLocaleXmlReader (object):
def __init__(self, filename): def __init__(self, filename: str) -> None:
self.root = self.__parse(filename) self.root: minidom.Element = self.__parse(filename)
from enumdata import language_map, script_map, territory_map from enumdata import language_map, script_map, territory_map
# Lists of (id, enum name, code, en.xml name) tuples: # Tuples of (id, enum name, code, en.xml name) tuples:
languages = tuple(self.__loadMap('language', language_map)) languages = tuple(self.__loadMap('language', language_map))
scripts = tuple(self.__loadMap('script', script_map)) scripts = tuple(self.__loadMap('script', script_map))
territories = tuple(self.__loadMap('territory', territory_map)) territories = tuple(self.__loadMap('territory', territory_map))
# as enum numeric values, tuple[tuple[int, int, int], tuple[int, int, int]]
self.__likely = tuple(self.__likelySubtagsMap()) self.__likely = tuple(self.__likelySubtagsMap())
# Mappings {ID: (enum name, code, en.xml name)} # Mappings {ID: (enum name, code, en.xml name)}
@ -69,14 +72,15 @@ class QLocaleXmlReader (object):
self.__dupes = set(v[1] for v in languages) & set(v[1] for v in territories) self.__dupes = set(v[1] for v in languages) & set(v[1] for v in territories)
self.cldrVersion = self.__firstChildText(self.root, "version") self.cldrVersion = self.__firstChildText(self.root, "version")
def loadLocaleMap(self, calendars, grumble = lambda text: None): def loadLocaleMap(self, calendars: Iterable[str], grumble = lambda text: None):
kid = self.__firstChildText kid: Callable[[minidom.Element, str], str] = self.__firstChildText
likely = dict(self.__likely) likely: dict[tuple[int, int, int], tuple[int, int, int]] = dict(self.__likely)
for elt in self.__eachEltInGroup(self.root, 'localeList', 'locale'): for elt in self.__eachEltInGroup(self.root, 'localeList', 'locale'):
locale = Locale.fromXmlData(lambda k: kid(elt, k), calendars) locale: Locale = Locale.fromXmlData(lambda k: kid(elt, k), calendars)
language = self.__langByName[locale.language][0] language: int = self.__langByName[locale.language][0]
script = self.__textByName[locale.script][0] script: int = self.__textByName[locale.script][0]
territory = self.__landByName[locale.territory][0] territory: int = self.__landByName[locale.territory][0]
if language != 1: # C if language != 1: # C
if territory == 0: if territory == 0:
@ -87,7 +91,8 @@ class QLocaleXmlReader (object):
# http://www.unicode.org/reports/tr35/#Likely_Subtags # http://www.unicode.org/reports/tr35/#Likely_Subtags
try: try:
try: try:
to = likely[(locale.language, 'AnyScript', locale.territory)] to: tuple[int, int, int] = likely[(locale.language, 'AnyScript',
locale.territory)]
except KeyError: except KeyError:
to = likely[(locale.language, 'AnyScript', 'AnyTerritory')] to = likely[(locale.language, 'AnyScript', 'AnyTerritory')]
except KeyError: except KeyError:
@ -98,22 +103,22 @@ class QLocaleXmlReader (object):
yield (language, script, territory), locale yield (language, script, territory), locale
def aliasToIana(self): def aliasToIana(self) -> Iterator[tuple[str, str]]:
kid = self.__firstChildText kid: Callable[[minidom.Element, str], str] = self.__firstChildText
for elt in self.__eachEltInGroup(self.root, 'zoneAliases', 'zoneAlias'): for elt in self.__eachEltInGroup(self.root, 'zoneAliases', 'zoneAlias'):
yield kid(elt, 'alias'), kid(elt, 'iana') yield kid(elt, 'alias'), kid(elt, 'iana')
def msToIana(self): def msToIana(self) -> Iterator[tuple[str, str]]:
kid = self.__firstChildText kid: Callable[[minidom.Element, str], str] = self.__firstChildText
for elt in self.__eachEltInGroup(self.root, 'windowsZone', 'msZoneIana'): for elt in self.__eachEltInGroup(self.root, 'windowsZone', 'msZoneIana'):
yield kid(elt, 'msid'), kid(elt, 'iana') yield kid(elt, 'msid'), kid(elt, 'iana')
def msLandIanas(self): def msLandIanas(self) -> Iterator[tuple[str, str, str]]:
kid = self.__firstChildText kid: Callable[[minidom.Element, str], str] = self.__firstChildText
for elt in self.__eachEltInGroup(self.root, 'windowsZone', 'msLandZones'): for elt in self.__eachEltInGroup(self.root, 'windowsZone', 'msLandZones'):
yield kid(elt, 'msid'), kid(elt, 'territorycode'), kid(elt, 'ianaids') yield kid(elt, 'msid'), kid(elt, 'territorycode'), kid(elt, 'ianaids')
def languageIndices(self, locales): def languageIndices(self, locales: tuple[int, ...]) -> Iterator[tuple[int, str]]:
index = 0 index = 0
for key, value in self.languages.items(): for key, value in self.languages.items():
i, count = 0, locales.count(key) i, count = 0, locales.count(key)
@ -122,14 +127,15 @@ class QLocaleXmlReader (object):
index += count index += count
yield i, value[0] yield i, value[0]
def likelyMap(self): def likelyMap(self) -> Iterator[tuple[str, tuple[int, int, int], str, tuple[int, int, int]]]:
def tag(t): def tag(t: tuple[tuple[int, str], tuple[int, str], tuple[int, str]]) -> Iterator[str]:
lang, script, land = t lang, script, land = t
yield lang[1] if lang[0] else 'und' yield lang[1] if lang[0] else 'und'
if script[0]: yield script[1] if script[0]: yield script[1]
if land[0]: yield land[1] if land[0]: yield land[1]
def ids(t): def ids(t: tuple[tuple[int, str], tuple[int, str], tuple[int, str]]
) -> tuple[int, int, int]:
return tuple(x[0] for x in t) return tuple(x[0] for x in t)
for pair in self.__likely: for pair in self.__likely:
@ -151,7 +157,7 @@ class QLocaleXmlReader (object):
self.__textByName[give[1]][0]), self.__textByName[give[1]][0]),
self.__landByName[give[2]][0]) self.__landByName[give[2]][0])
def enumify(self, name, suffix): def enumify(self, name: str, suffix: str) -> str:
"""Stick together the parts of an enumdata.py name. """Stick together the parts of an enumdata.py name.
Names given in enumdata.py include spaces and hyphens that we Names given in enumdata.py include spaces and hyphens that we
@ -178,17 +184,21 @@ class QLocaleXmlReader (object):
return name return name
# Implementation details: # Implementation details:
def __loadMap(self, category, enum): def __loadMap(self, category: str, enum: dict[int, tuple[str, str]]
) -> Iterator[tuple[int, str, str, str]]:
kid = self.__firstChildText kid = self.__firstChildText
for element in self.__eachEltInGroup(self.root, f'{category}List', category): for element in self.__eachEltInGroup(self.root, f'{category}List', category):
key = int(kid(element, 'id')) key = int(kid(element, 'id'))
yield key, enum[key][0], kid(element, 'code'), kid(element, 'name') yield key, enum[key][0], kid(element, 'code'), kid(element, 'name')
def __likelySubtagsMap(self): # Likely subtag management:
def triplet(element, keys=('language', 'script', 'territory'), kid = self.__firstChildText): def __likelySubtagsMap(self) -> Iterator[tuple[tuple[int, int, int], tuple[int, int, int]]]:
def triplet(element: minidom.Element,
keys: tuple[str, str, str]=('language', 'script', 'territory'),
kid = self.__firstChildText) -> tuple[str, str, str]:
return tuple(kid(element, key) for key in keys) return tuple(kid(element, key) for key in keys)
kid = self.__firstChildElt kid: Callable[[minidom.Element, str], minidom.Element] = self.__firstChildElt
for elt in self.__eachEltInGroup(self.root, 'likelySubtags', 'likelySubtag'): for elt in self.__eachEltInGroup(self.root, 'likelySubtags', 'likelySubtag'):
yield triplet(kid(elt, "from")), triplet(kid(elt, "to")) yield triplet(kid(elt, "from")), triplet(kid(elt, "to"))
@ -198,17 +208,18 @@ class QLocaleXmlReader (object):
# DOM access: # DOM access:
from xml.dom import minidom from xml.dom import minidom
@staticmethod @staticmethod
def __parse(filename, read = minidom.parse): def __parse(filename: str, read = minidom.parse) -> minidom.Element:
return read(filename).documentElement return read(filename).documentElement
@staticmethod @staticmethod
def __isNodeNamed(elt, name, TYPE=minidom.Node.ELEMENT_NODE): def __isNodeNamed(elt: minidom.Element|minidom.Text, name: str,
TYPE: int = minidom.Node.ELEMENT_NODE) -> bool:
return elt.nodeType == TYPE and elt.nodeName == name return elt.nodeType == TYPE and elt.nodeName == name
del minidom del minidom
@staticmethod @staticmethod
def __eltWords(elt): def __eltWords(elt: minidom.Element) -> Iterator[str]:
child = elt.firstChild child: minidom.Text|minidom.CDATASection|None = elt.firstChild
while child: while child:
if child.nodeType == elt.TEXT_NODE: if child.nodeType == elt.TEXT_NODE:
# Note: do not strip(), as some group separators are # Note: do not strip(), as some group separators are
@ -217,8 +228,8 @@ class QLocaleXmlReader (object):
child = child.nextSibling child = child.nextSibling
@classmethod @classmethod
def __firstChildElt(cls, parent, name): def __firstChildElt(cls, parent: minidom.Element, name: str) -> minidom.Element:
child = parent.firstChild child: minidom.Text|minidom.Element = parent.firstChild
while child: while child:
if cls.__isNodeNamed(child, name): if cls.__isNodeNamed(child, name):
return child return child
@ -227,13 +238,14 @@ class QLocaleXmlReader (object):
raise Error(f'No {name} child found') raise Error(f'No {name} child found')
@classmethod @classmethod
def __firstChildText(cls, elt, key): def __firstChildText(cls, elt: minidom.Element, key: str) -> str:
return ' '.join(cls.__eltWords(cls.__firstChildElt(elt, key))) return ' '.join(cls.__eltWords(cls.__firstChildElt(elt, key)))
@classmethod @classmethod
def __eachEltInGroup(cls, parent, group, key): def __eachEltInGroup(cls, parent: minidom.Element, group: str, key: str
) -> Iterator[minidom.Element]:
try: try:
element = cls.__firstChildElt(parent, group).firstChild element: minidom.Element = cls.__firstChildElt(parent, group).firstChild
except Error: except Error:
element = None element = None