Add type hints to LocaleSourceEditor and TimeZoneDataWriter

Task-number: QTBUG-128634
Pick-to: 6.8
Change-Id: I5dabb5e721b610bc9edb01b86aa173d03c36a48a
Reviewed-by: Edward Welbourne <edward.welbourne@qt.io>
This commit is contained in:
Mate Barany 2024-09-19 17:28:20 +02:00
parent c1ffb6e751
commit dd698dcb4d

View File

@ -19,7 +19,7 @@ import argparse
from pathlib import Path from pathlib import Path
from typing import Callable, Iterator, Optional from typing import Callable, Iterator, Optional
from qlocalexml import QLocaleXmlReader from qlocalexml import Locale, QLocaleXmlReader
from localetools import * from localetools import *
from iso639_3 import LanguageCodeData from iso639_3 import LanguageCodeData
from zonedata import utcIdList, windowsIdList from zonedata import utcIdList, windowsIdList
@ -173,7 +173,7 @@ def currencyIsoCodeData(s: str) -> str:
return "{0,0,0}" return "{0,0,0}"
class LocaleSourceEditor (SourceFileEditor): class LocaleSourceEditor (SourceFileEditor):
def __init__(self, path: Path, temp: Path, version: str): def __init__(self, path: Path, temp: Path, version: str) -> None:
super().__init__(path, temp) super().__init__(path, temp)
self.version = version self.version = version
@ -194,54 +194,58 @@ class LocaleSourceEditor (SourceFileEditor):
""") """)
class TimeZoneDataWriter (LocaleSourceEditor): class TimeZoneDataWriter (LocaleSourceEditor):
def __init__(self, path: Path, temp: Path, version: str): def __init__(self, path: Path, temp: Path, version: str) -> None:
super().__init__(path, temp, version) super().__init__(path, temp, version)
self.__ianaTable = ByteArrayData() # Single IANA IDs self.__ianaTable = ByteArrayData() # Single IANA IDs
self.__ianaListTable = ByteArrayData() # Space-joined lists of IDs self.__ianaListTable = ByteArrayData() # Space-joined lists of IDs
self.__windowsTable = ByteArrayData() # Windows names for zones self.__windowsTable = ByteArrayData() # Windows names for zones
self.__metaIdData = ByteArrayData() # Metazone names self.__metaIdData = ByteArrayData() # Metazone names
self.__windowsList = sorted(windowsIdList, self.__windowsList: list[tuple[str, int]] = sorted(windowsIdList,
key=lambda p: p[0].lower()) key=lambda p: p[0].lower())
self.windowsKey = {name: (key, off) for key, (name, off) self.windowsKey: dict[str, tuple[int, int]] = {name: (key, off) for key, (name, off)
in enumerate(self.__windowsList, 1)} in enumerate(self.__windowsList, 1)}
from enumdata import territory_map from enumdata import territory_map
self.__landKey = {code: (i, name) for i, (name, code) in territory_map.items()} self.__landKey: dict[str, tuple[int, str]] = {code: (i, name) for i, (name, code)
in territory_map.items()}
def utcTable(self): def utcTable(self) -> None:
offsetMap, out = {}, self.writer.write offsetMap: dict[int, tuple[str, ...]] = {}
out: Callable[[str], int] = self.writer.write
for name in utcIdList: for name in utcIdList:
offset = self.__offsetOf(name) offset: int = self.__offsetOf(name)
offsetMap[offset] = offsetMap.get(offset, ()) + (name,) offsetMap[offset] = offsetMap.get(offset, ()) + (name,)
# Write UTC ID key table # Write UTC ID key table
out('\n// IANA List Index, UTC Offset\n') out('\n// IANA List Index, UTC Offset\n')
out('static constexpr UtcData utcDataTable[] = {\n') out('static constexpr UtcData utcDataTable[] = {\n')
for offset in sorted(offsetMap.keys()): # Sort so C++ can binary-chop. for offset in sorted(offsetMap.keys()): # Sort so C++ can binary-chop.
names = offsetMap[offset]; names: tuple[str, ...] = offsetMap[offset]
joined = self.__ianaListTable.append(' '.join(names)) joined: int = self.__ianaListTable.append(' '.join(names))
out(f' {{ {joined:6d},{offset:6d} }}, // {names[0]}\n') out(f' {{ {joined:6d},{offset:6d} }}, // {names[0]}\n')
out('};\n') out('};\n')
def aliasToIana(self, pairs): def aliasToIana(self, pairs: Iterator[tuple[str, str]]) -> None:
out, store = self.writer.write, self.__ianaTable.append out: Callable[[str], int] = self.writer.write
store: Callable[[str], int] = self.__ianaTable.append
out('// IANA ID indices of alias and IANA ID\n') out('// IANA ID indices of alias and IANA ID\n')
out('static constexpr AliasData aliasMappingTable[] = {\n') out('static constexpr AliasData aliasMappingTable[] = {\n')
for name, iana in pairs: # They're ready-sorted for name, iana in pairs: # They're ready-sorted
assert name != iana, (alias, iana) # Filtered out in QLocaleXmlWriter assert name != iana, (name, iana) # Filtered out in QLocaleXmlWriter
out(f' {{ {store(name):6d},{store(iana):6d} }},' out(f' {{ {store(name):6d},{store(iana):6d} }},'
f' // {name} -> {iana}\n') f' // {name} -> {iana}\n')
out('};\n\n') out('};\n\n')
def territoryZone(self, pairs): def territoryZone(self, pairs: Iterator[tuple[str, str]]) -> None:
self.__beginNonIcuFeatureTZL() self.__beginNonIcuFeatureTZL()
out, store = self.writer.write, self.__ianaTable.append out: Callable[[str], int] = self.writer.write
landKey = self.__landKey store: Callable[[str], int] = self.__ianaTable.append
seq = sorted((landKey[code][0], iana, landKey[code][1]) landKey: dict[str, tuple[int, str]] = self.__landKey
for code, iana in pairs) seq: list[tuple[int, str, str]] = sorted((landKey[code][0], iana, landKey[code][1])
for code, iana in pairs)
# Write territory-to-zone table # Write territory-to-zone table
out('\n// QLocale::Territory value, IANA ID Index\n') out('\n// QLocale::Territory value, IANA ID Index\n')
out('static constexpr TerritoryZone territoryZoneMap[] = {\n') out('static constexpr TerritoryZone territoryZoneMap[] = {\n')
@ -252,13 +256,15 @@ class TimeZoneDataWriter (LocaleSourceEditor):
# self.__endNonIcuFeatureTZL() # self.__endNonIcuFeatureTZL()
def metaLandZone(self, quads): def metaLandZone(self, quads: Iterator[tuple[str, int, str, str]]) -> None:
# self.__beginNonIcuFeatureTZL() # self.__beginNonIcuFeatureTZL()
out, metaStore = self.writer.write, self.__metaIdData.append out: Callable[[str], int] = self.writer.write
ianaStore = self.__ianaTable.append metaStore: Callable[[str], int] = self.__metaIdData.append
landKey = self.__landKey ianaStore: Callable[[str], int] = self.__ianaTable.append
seq = sorted((metaKey, landKey[land][0], meta, landKey[land][1], iana) landKey: dict[str, tuple[int, str]] = self.__landKey
for meta, metaKey, land, iana in quads) seq: list[tuple[int, int, str, str, str]] = sorted(
(metaKey, landKey[land][0], meta, landKey[land][1], iana)
for meta, metaKey, land, iana in quads)
# Write (metazone, territory, zone) table # Write (metazone, territory, zone) table
out('\n// MetaZone Key, MetaZone Name Index, ' out('\n// MetaZone Key, MetaZone Name Index, '
@ -272,10 +278,11 @@ class TimeZoneDataWriter (LocaleSourceEditor):
# self.__endNonIcuFeatureTZL() # self.__endNonIcuFeatureTZL()
def zoneMetaStory(self, quads): def zoneMetaStory(self, quads: Iterator[tuple[str, int, int, int]]) -> None:
# self.__beginNonIcuFeatureTZL() # self.__beginNonIcuFeatureTZL()
out, store = self.writer.write, self.__ianaTable.append out: Callable[[str], int] = self.writer.write
store: Callable[[str], int] = self.__ianaTable.append
# Write (zone, metazone key, begin, end) table: # Write (zone, metazone key, begin, end) table:
out('\n// IANA ID Index, MetaZone Key, interval start, end\n') out('\n// IANA ID Index, MetaZone Key, interval start, end\n')
@ -287,10 +294,11 @@ class TimeZoneDataWriter (LocaleSourceEditor):
self.__endNonIcuFeatureTZL() self.__endNonIcuFeatureTZL()
def msToIana(self, pairs): def msToIana(self, pairs: Iterator[tuple[str, str]]) -> None:
out, winStore = self.writer.write, self.__windowsTable.append out: Callable[[str], int] = self.writer.write
ianaStore = self.__ianaTable.append winStore: Callable[[str], int] = self.__windowsTable.append
alias = dict(pairs) # {MS name: IANA ID} ianaStore: Callable[[str], int] = self.__ianaTable.append
alias: dict[str, str] = dict(pairs) # {MS name: IANA ID}
assert all(not any(x.isspace() for x in iana) for iana in alias.values()) assert all(not any(x.isspace() for x in iana) for iana in alias.values())
out('\n// Windows ID Key, Windows ID Index, IANA ID Index, UTC Offset\n') out('\n// Windows ID Key, Windows ID Index, IANA ID Index, UTC Offset\n')
@ -302,12 +310,14 @@ class TimeZoneDataWriter (LocaleSourceEditor):
f'{ianaStore(alias[name]):6d},{offset:6d} }}, // {name}\n') f'{ianaStore(alias[name]):6d},{offset:6d} }}, // {name}\n')
out('};\n') out('};\n')
def msLandIanas(self, triples): # (MS name, territory code, IANA list) def msLandIanas(self, triples: Iterator[tuple[str, str, str]]) -> None:
out, store = self.writer.write, self.__ianaListTable.append # triples (MS name, territory code, IANA list)
landKey = self.__landKey out: Callable[[str], int] = self.writer.write
seq = sorted((self.windowsKey[name][0], landKey[land][0], store: Callable[[str], int] = self.__ianaListTable.append
name, landKey[land][1], ianas) landKey: dict[str, tuple[int, str]] = self.__landKey
for name, land, ianas in triples) seq: list[tuple[int, int, str, str, str]] = sorted(
(self.windowsKey[name][0], landKey[land][0], name, landKey[land][1], ianas)
for name, land, ianas in triples)
out('// Windows ID Key, Territory Enum, IANA List Index\n') out('// Windows ID Key, Territory Enum, IANA List Index\n')
out('static constexpr ZoneData zoneDataTable[] = {\n') out('static constexpr ZoneData zoneDataTable[] = {\n')
@ -317,7 +327,7 @@ class TimeZoneDataWriter (LocaleSourceEditor):
f' // {name} / {land}\n') f' // {name} / {land}\n')
out('};\n') out('};\n')
def nameTables(self, locales): def nameTables(self, locales: Iterator[Locale]) -> tuple[ByteArrayData, ByteArrayData]:
"""Ensure all zone and metazone names used by locales are known """Ensure all zone and metazone names used by locales are known
Must call before writeTables(), to ensure zone and metazone naming Must call before writeTables(), to ensure zone and metazone naming
@ -340,7 +350,7 @@ class TimeZoneDataWriter (LocaleSourceEditor):
self.__metaIdData.append(k) self.__metaIdData.append(k)
return self.__ianaTable, self.__metaIdData return self.__ianaTable, self.__metaIdData
def writeTables(self): def writeTables(self) -> None:
self.__windowsTable.write(self.writer.write, 'windowsIdData') self.__windowsTable.write(self.writer.write, 'windowsIdData')
self.__ianaListTable.write(self.writer.write, 'ianaListData') self.__ianaListTable.write(self.writer.write, 'ianaListData')
self.__ianaTable.write(self.writer.write, 'ianaIdData') self.__ianaTable.write(self.writer.write, 'ianaIdData')
@ -350,13 +360,13 @@ class TimeZoneDataWriter (LocaleSourceEditor):
self.writer.write('\n') self.writer.write('\n')
# Implementation details: # Implementation details:
def __beginNonIcuFeatureTZL(self): def __beginNonIcuFeatureTZL(self) -> None:
self.writer.write('\n#if QT_CONFIG(timezone_locale) && !QT_CONFIG(icu)\n') self.writer.write('\n#if QT_CONFIG(timezone_locale) && !QT_CONFIG(icu)\n')
def __endNonIcuFeatureTZL(self): def __endNonIcuFeatureTZL(self) -> None:
self.writer.write('\n#endif // timezone_locale but not ICU\n') self.writer.write('\n#endif // timezone_locale but not ICU\n')
@staticmethod @staticmethod
def __offsetOf(utcName): def __offsetOf(utcName: str) -> int:
"Maps a UTC±HH:mm name to its offset in seconds" "Maps a UTC±HH:mm name to its offset in seconds"
assert utcName.startswith('UTC') assert utcName.startswith('UTC')
if len(utcName) == 3: if len(utcName) == 3: