More pyugrade to 3.9

This commit is contained in:
Kovid Goyal 2024-08-05 10:59:50 +05:30
parent a35f7e060b
commit 2b3f2258ff
No known key found for this signature in database
GPG key ID: 06BC317B515ACE7C
12 changed files with 88 additions and 110 deletions

View file

@ -4,10 +4,9 @@
import os import os
import sys import sys
from typing import List
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) os.chdir(os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
sys.path.insert(0, os.getcwd()) sys.path.insert(0, os.getcwd())
if len(args) == 1: if len(args) == 1:

View file

@ -5,18 +5,18 @@
import subprocess import subprocess
import sys import sys
from collections import defaultdict from collections import defaultdict
from typing import Any, DefaultDict, Dict, FrozenSet, List, Tuple, Union from typing import Any, DefaultDict, Union
if __name__ == '__main__' and not __package__: if __name__ == '__main__' and not __package__:
import __main__ import __main__
__main__.__package__ = 'gen' __main__.__package__ = 'gen'
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
KeymapType = Dict[str, Tuple[str, Union[FrozenSet[str], str]]] KeymapType = dict[str, tuple[str, Union[frozenset[str], str]]]
def resolve_keys(keymap: KeymapType) -> DefaultDict[str, List[str]]: def resolve_keys(keymap: KeymapType) -> DefaultDict[str, list[str]]:
ans: DefaultDict[str, List[str]] = defaultdict(list) ans: DefaultDict[str, list[str]] = defaultdict(list)
for ch, (attr, atype) in keymap.items(): for ch, (attr, atype) in keymap.items():
if isinstance(atype, str) and atype in ('int', 'uint'): if isinstance(atype, str) and atype in ('int', 'uint'):
q = atype q = atype
@ -45,7 +45,7 @@ def parse_key(keymap: KeymapType) -> str:
return ' \n'.join(lines) return ' \n'.join(lines)
def parse_flag(keymap: KeymapType, type_map: Dict[str, Any], command_class: str) -> str: def parse_flag(keymap: KeymapType, type_map: dict[str, Any], command_class: str) -> str:
lines = [] lines = []
for ch in type_map['flag']: for ch in type_map['flag']:
attr, allowed_values = keymap[ch] attr, allowed_values = keymap[ch]
@ -63,14 +63,14 @@ def parse_flag(keymap: KeymapType, type_map: Dict[str, Any], command_class: str)
return ' \n'.join(lines) return ' \n'.join(lines)
def parse_number(keymap: KeymapType) -> Tuple[str, str]: def parse_number(keymap: KeymapType) -> tuple[str, str]:
int_keys = [f'I({attr})' for attr, atype in keymap.values() if atype == 'int'] int_keys = [f'I({attr})' for attr, atype in keymap.values() if atype == 'int']
uint_keys = [f'U({attr})' for attr, atype in keymap.values() if atype == 'uint'] uint_keys = [f'U({attr})' for attr, atype in keymap.values() if atype == 'uint']
return '; '.join(int_keys), '; '.join(uint_keys) return '; '.join(int_keys), '; '.join(uint_keys)
def cmd_for_report(report_name: str, keymap: KeymapType, type_map: Dict[str, Any], payload_allowed: bool) -> str: def cmd_for_report(report_name: str, keymap: KeymapType, type_map: dict[str, Any], payload_allowed: bool) -> str:
def group(atype: str, conv: str) -> Tuple[str, str]: def group(atype: str, conv: str) -> tuple[str, str]:
flag_fmt, flag_attrs = [], [] flag_fmt, flag_attrs = [], []
cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype] cv = {'flag': 'c', 'int': 'i', 'uint': 'I'}[atype]
for ch in type_map[atype]: for ch in type_map[atype]:
@ -293,7 +293,7 @@ def graphics_parser() -> None:
write_header(text, 'kitty/parse-graphics-command.h') write_header(text, 'kitty/parse-graphics-command.h')
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
graphics_parser() graphics_parser()

View file

@ -6,7 +6,6 @@
import re import re
import subprocess import subprocess
import sys import sys
from typing import List
from kitty.conf.generate import write_output from kitty.conf.generate import write_output
@ -16,7 +15,7 @@
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
def patch_color_list(path: str, colors: List[str], name: str, spc: str = ' ') -> None: def patch_color_list(path: str, colors: list[str], name: str, spc: str = ' ') -> None:
with open(path, 'r+') as f: with open(path, 'r+') as f:
raw = f.read() raw = f.read()
colors = sorted(colors) colors = sorted(colors)
@ -40,7 +39,7 @@ def patch_color_list(path: str, colors: List[str], name: str, spc: str = ' ')
subprocess.check_call(['gofmt', '-w', path]) subprocess.check_call(['gofmt', '-w', path])
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
from kitty.options.definition import definition from kitty.options.definition import definition
nullable_colors = [] nullable_colors = []
all_colors = [] all_colors = []

View file

@ -4,7 +4,6 @@
import os import os
import subprocess import subprocess
import sys import sys
from typing import List
if __name__ == '__main__' and not __package__: if __name__ == '__main__' and not __package__:
import __main__ import __main__
@ -58,7 +57,7 @@
''' '''
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
glfw_enum = [] glfw_enum = []
css_names = [] css_names = []
glfw_xc_map = {} glfw_xc_map = {}

View file

@ -12,20 +12,15 @@
import subprocess import subprocess
import sys import sys
import tarfile import tarfile
from collections.abc import Iterator, Sequence
from contextlib import contextmanager, suppress from contextlib import contextmanager, suppress
from functools import lru_cache from functools import lru_cache
from itertools import chain from itertools import chain
from typing import ( from typing import (
Any, Any,
BinaryIO, BinaryIO,
Dict,
Iterator,
List,
Optional, Optional,
Sequence,
Set,
TextIO, TextIO,
Tuple,
Union, Union,
) )
@ -56,7 +51,7 @@
sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__)))) sys.path.insert(0, os.path.dirname(os.path.dirname(os.path.abspath(__file__))))
changed: List[str] = [] changed: list[str] = []
def newer(dest: str, *sources: str) -> bool: def newer(dest: str, *sources: str) -> bool:
@ -74,7 +69,7 @@ def newer(dest: str, *sources: str) -> bool:
# Utils {{{ # Utils {{{
def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int], Dict[str, str]]) -> str: def serialize_go_dict(x: Union[dict[str, int], dict[int, str], dict[int, int], dict[str, str]]) -> str:
ans = [] ans = []
def s(x: Union[int, str]) -> str: def s(x: Union[int, str]) -> str:
@ -192,7 +187,7 @@ def kitten_cli_docs(kitten: str) -> Any:
@lru_cache @lru_cache
def go_options_for_kitten(kitten: str) -> Tuple[Sequence[GoOption], Optional[CompletionSpec]]: def go_options_for_kitten(kitten: str) -> tuple[Sequence[GoOption], Optional[CompletionSpec]]:
kcd = kitten_cli_docs(kitten) kcd = kitten_cli_docs(kitten)
if kcd: if kcd:
ospec = kcd['options'] ospec = kcd['options']
@ -297,7 +292,7 @@ def generate_completions_for_kitty() -> None:
# rc command wrappers {{{ # rc command wrappers {{{
json_field_types: Dict[str, str] = { json_field_types: dict[str, str] = {
'bool': 'bool', 'str': 'escaped_string', 'list.str': '[]escaped_string', 'dict.str': 'map[escaped_string]escaped_string', 'float': 'float64', 'int': 'int', 'bool': 'bool', 'str': 'escaped_string', 'list.str': '[]escaped_string', 'dict.str': 'map[escaped_string]escaped_string', 'float': 'float64', 'int': 'int',
'scroll_amount': 'any', 'spacing': 'any', 'colors': 'any', 'scroll_amount': 'any', 'spacing': 'any', 'colors': 'any',
} }
@ -338,20 +333,20 @@ def go_declaration(self) -> str:
def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) -> str: def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) -> str:
template = '\n' + template[len('//go:build exclude'):] template = '\n' + template[len('//go:build exclude'):]
af: List[str] = [] af: list[str] = []
a = af.append a = af.append
af.extend(cmd.args.as_go_completion_code('ans')) af.extend(cmd.args.as_go_completion_code('ans'))
od: List[str] = [] od: list[str] = []
option_map: Dict[str, GoOption] = {} option_map: dict[str, GoOption] = {}
for o in rc_command_options(name): for o in rc_command_options(name):
option_map[o.go_var_name] = o option_map[o.go_var_name] = o
a(o.as_option('ans')) a(o.as_option('ans'))
if o.go_var_name in ('NoResponse', 'ResponseTimeout'): if o.go_var_name in ('NoResponse', 'ResponseTimeout'):
continue continue
od.append(o.struct_declaration()) od.append(o.struct_declaration())
jd: List[str] = [] jd: list[str] = []
json_fields = [] json_fields = []
field_types: Dict[str, str] = {} field_types: dict[str, str] = {}
for line in cmd.protocol_spec.splitlines(): for line in cmd.protocol_spec.splitlines():
line = line.strip() line = line.strip()
if ':' not in line: if ':' not in line:
@ -360,8 +355,8 @@ def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) ->
json_fields.append(f) json_fields.append(f)
field_types[f.field] = f.field_type field_types[f.field] = f.field_type
jd.append(f.go_declaration()) jd.append(f.go_declaration())
jc: List[str] = [] jc: list[str] = []
handled_fields: Set[str] = set() handled_fields: set[str] = set()
jc.extend(cmd.args.as_go_code(name, field_types, handled_fields)) jc.extend(cmd.args.as_go_code(name, field_types, handled_fields))
unhandled = {} unhandled = {}
@ -429,7 +424,7 @@ def go_code_for_remote_command(name: str, cmd: RemoteCommand, template: str) ->
# kittens {{{ # kittens {{{
@lru_cache @lru_cache
def wrapped_kittens() -> Tuple[str, ...]: def wrapped_kittens() -> tuple[str, ...]:
with open('shell-integration/ssh/kitty') as f: with open('shell-integration/ssh/kitty') as f:
for line in f: for line in f:
if line.startswith(' wrapped_kittens="'): if line.startswith(' wrapped_kittens="'):
@ -574,7 +569,7 @@ def generate_color_names() -> str:
''' '''
def load_ref_map() -> Dict[str, Dict[str, str]]: def load_ref_map() -> dict[str, dict[str, str]]:
with open('kitty/docs_ref_map_generated.h') as f: with open('kitty/docs_ref_map_generated.h') as f:
raw = f.read() raw = f.read()
raw = raw.split('{', 1)[1].split('}', 1)[0] raw = raw.split('{', 1)[1].split('}', 1)[0]
@ -654,7 +649,7 @@ def replace_if_needed(path: str, show_diff: bool = False) -> Iterator[io.StringI
finally: finally:
sys.stdout = origb sys.stdout = origb
orig = '' orig = ''
with suppress(FileNotFoundError), open(path, 'r') as f: with suppress(FileNotFoundError), open(path) as f:
orig = f.read() orig = f.read()
new = buf.getvalue() new = buf.getvalue()
new = f'// Code generated by {os.path.basename(__file__)}; DO NOT EDIT.\n\n' + new new = f'// Code generated by {os.path.basename(__file__)}; DO NOT EDIT.\n\n' + new
@ -670,7 +665,7 @@ def replace_if_needed(path: str, show_diff: bool = False) -> Iterator[io.StringI
@lru_cache(maxsize=256) @lru_cache(maxsize=256)
def rc_command_options(name: str) -> Tuple[GoOption, ...]: def rc_command_options(name: str) -> tuple[GoOption, ...]:
cmd = command_for_name(name) cmd = command_for_name(name)
return tuple(go_options_for_seq(parse_option_spec(cmd.options_spec or '\n\n')[0])) return tuple(go_options_for_seq(parse_option_spec(cmd.options_spec or '\n\n')[0]))
@ -880,7 +875,7 @@ def start_simdgen() -> 'subprocess.Popen[bytes]':
return subprocess.Popen(['go', 'run', 'generate.go'], cwd='tools/simdstring', stdout=subprocess.PIPE, stderr=subprocess.PIPE) return subprocess.Popen(['go', 'run', 'generate.go'], cwd='tools/simdstring', stdout=subprocess.PIPE, stderr=subprocess.PIPE)
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
simdgen_process = start_simdgen() simdgen_process = start_simdgen()
with replace_if_needed('constants_generated.go') as f: with replace_if_needed('constants_generated.go') as f:
f.write(generate_constants()) f.write(generate_constants())

View file

@ -6,7 +6,7 @@
import subprocess import subprocess
import sys import sys
from pprint import pformat from pprint import pformat
from typing import Any, Dict, List, Union from typing import Any, Union
if __name__ == '__main__' and not __package__: if __name__ == '__main__' and not __package__:
import __main__ import __main__
@ -194,11 +194,11 @@
0x31: ord(' '), 0x31: ord(' '),
} # }}} } # }}}
functional_key_names: List[str] = [] functional_key_names: list[str] = []
name_to_code: Dict[str, int] = {} name_to_code: dict[str, int] = {}
name_to_xkb: Dict[str, str] = {} name_to_xkb: dict[str, str] = {}
name_to_vk: Dict[str, int] = {} name_to_vk: dict[str, int] = {}
name_to_macu: Dict[str, str] = {} name_to_macu: dict[str, str] = {}
start_code = 0xe000 start_code = 0xe000
for line in functional_key_defs.splitlines(): for line in functional_key_defs.splitlines():
line = line.strip() line = line.strip()
@ -254,11 +254,11 @@ def patch_file(path: str, what: str, text: str, start_marker: str = '/* ', end_m
subprocess.check_call(['go', 'fmt', path]) subprocess.check_call(['go', 'fmt', path])
def serialize_dict(x: Dict[Any, Any]) -> str: def serialize_dict(x: dict[Any, Any]) -> str:
return pformat(x, indent=4).replace('{', '{\n ', 1) return pformat(x, indent=4).replace('{', '{\n ', 1)
def serialize_go_dict(x: Union[Dict[str, int], Dict[int, str], Dict[int, int]]) -> str: def serialize_go_dict(x: Union[dict[str, int], dict[int, str], dict[int, int]]) -> str:
ans = [] ans = []
def s(x: Union[int, str]) -> str: def s(x: Union[int, str]) -> str:
@ -332,7 +332,7 @@ def generate_functional_table() -> None:
patch_file('kitty/key_encoding.c', 'special numbers', '\n'.join(enc_lines)) patch_file('kitty/key_encoding.c', 'special numbers', '\n'.join(enc_lines))
code_to_name = {v: k.upper() for k, v in name_to_code.items()} code_to_name = {v: k.upper() for k, v in name_to_code.items()}
csi_map = {v: name_to_code[k] for k, v in functional_encoding_overrides.items()} csi_map = {v: name_to_code[k] for k, v in functional_encoding_overrides.items()}
letter_trailer_codes: Dict[str, int] = { letter_trailer_codes: dict[str, int] = {
v: functional_encoding_overrides.get(k, name_to_code.get(k, 0)) v: functional_encoding_overrides.get(k, name_to_code.get(k, 0))
for k, v in different_trailer_functionals.items() if v in 'ABCDEHFPQRSZ'} for k, v in different_trailer_functionals.items() if v in 'ABCDEHFPQRSZ'}
text = f'functional_key_number_to_name_map = {serialize_dict(code_to_name)}' text = f'functional_key_number_to_name_map = {serialize_dict(code_to_name)}'
@ -377,7 +377,7 @@ def simple(c: str) -> None:
patch_file('kitty_tests/keys.py', 'legacy letter tests', '\n'.join(tests), start_marker='# ', end_marker='') patch_file('kitty_tests/keys.py', 'legacy letter tests', '\n'.join(tests), start_marker='# ', end_marker='')
def chunks(lst: List[Any], n: int) -> Any: def chunks(lst: list[Any], n: int) -> Any:
"""Yield successive n-sized chunks from lst.""" """Yield successive n-sized chunks from lst."""
for i in range(0, len(lst), n): for i in range(0, len(lst), n):
yield lst[i:i + n] yield lst[i:i + n]
@ -427,7 +427,7 @@ def generate_macos_mapping() -> None:
patch_file('glfw/cocoa_window.m', 'functional to macu', '\n'.join(lines)) patch_file('glfw/cocoa_window.m', 'functional to macu', '\n'.join(lines))
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
generate_glfw_header() generate_glfw_header()
generate_xkb_mapping() generate_xkb_mapping()
generate_functional_table() generate_functional_table()

View file

@ -1,10 +1,8 @@
#!/usr/bin/env python #!/usr/bin/env python
# vim:fileencoding=utf-8
import os import os
import sys import sys
from functools import lru_cache from functools import lru_cache
from typing import List
if __name__ == '__main__' and not __package__: if __name__ == '__main__' and not __package__:
import __main__ import __main__
@ -20,12 +18,12 @@ def to_linear(a: float) -> float:
@lru_cache @lru_cache
def generate_srgb_lut(line_prefix: str = ' ') -> List[str]: def generate_srgb_lut(line_prefix: str = ' ') -> list[str]:
values: List[str] = [] values: list[str] = []
lines: List[str] = [] lines: list[str] = []
for i in range(256): for i in range(256):
values.append('{:1.5f}f'.format(to_linear(i / 255.0))) values.append(f'{to_linear(i / 255.0):1.5f}f')
for i in range(16): for i in range(16):
lines.append(line_prefix + ', '.join(values[i * 16:(i + 1) * 16]) + ',') lines.append(line_prefix + ', '.join(values[i * 16:(i + 1) * 16]) + ',')
@ -35,7 +33,7 @@ def generate_srgb_lut(line_prefix: str = ' ') -> List[str]:
def generate_srgb_gamma(declaration: str = 'static const GLfloat srgb_lut[256] = {', close: str = '};') -> str: def generate_srgb_gamma(declaration: str = 'static const GLfloat srgb_lut[256] = {', close: str = '};') -> str:
lines: List[str] = [] lines: list[str] = []
a = lines.append a = lines.append
a('// Generated by gen-srgb-lut.py DO NOT edit') a('// Generated by gen-srgb-lut.py DO NOT edit')
@ -47,7 +45,7 @@ def generate_srgb_gamma(declaration: str = 'static const GLfloat srgb_lut[256] =
return "\n".join(lines) return "\n".join(lines)
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
c = generate_srgb_gamma() c = generate_srgb_gamma()
with open(os.path.join('kitty', 'srgb_gamma.h'), 'w') as f: with open(os.path.join('kitty', 'srgb_gamma.h'), 'w') as f:
f.write(f'{c}\n') f.write(f'{c}\n')

View file

@ -6,6 +6,7 @@
import subprocess import subprocess
import sys import sys
from collections import defaultdict from collections import defaultdict
from collections.abc import Generator, Iterable
from contextlib import contextmanager from contextlib import contextmanager
from functools import lru_cache, partial from functools import lru_cache, partial
from html.entities import html5 from html.entities import html5
@ -14,14 +15,7 @@
from typing import ( from typing import (
Callable, Callable,
DefaultDict, DefaultDict,
Dict,
FrozenSet,
Generator,
Iterable,
List,
Optional, Optional,
Set,
Tuple,
Union, Union,
) )
from urllib.request import urlopen from urllib.request import urlopen
@ -58,7 +52,7 @@ def get_data(fname: str, folder: str = 'UCD') -> Iterable[str]:
@lru_cache(maxsize=2) @lru_cache(maxsize=2)
def unicode_version() -> Tuple[int, int, int]: def unicode_version() -> tuple[int, int, int]:
for line in get_data("ReadMe.txt"): for line in get_data("ReadMe.txt"):
m = re.search(r'Version\s+(\d+)\.(\d+)\.(\d+)', line) m = re.search(r'Version\s+(\d+)\.(\d+)\.(\d+)', line)
if m is not None: if m is not None:
@ -67,16 +61,16 @@ def unicode_version() -> Tuple[int, int, int]:
# Map of class names to set of codepoints in class # Map of class names to set of codepoints in class
class_maps: Dict[str, Set[int]] = {} class_maps: dict[str, set[int]] = {}
all_symbols: Set[int] = set() all_symbols: set[int] = set()
name_map: Dict[int, str] = {} name_map: dict[int, str] = {}
word_search_map: DefaultDict[str, Set[int]] = defaultdict(set) word_search_map: DefaultDict[str, set[int]] = defaultdict(set)
soft_hyphen = 0xad soft_hyphen = 0xad
flag_codepoints = frozenset(range(0x1F1E6, 0x1F1E6 + 26)) flag_codepoints = frozenset(range(0x1F1E6, 0x1F1E6 + 26))
# See https://github.com/harfbuzz/harfbuzz/issues/169 # See https://github.com/harfbuzz/harfbuzz/issues/169
marks = set(emoji_skin_tone_modifiers) | flag_codepoints marks = set(emoji_skin_tone_modifiers) | flag_codepoints
not_assigned = set(range(0, sys.maxunicode)) not_assigned = set(range(0, sys.maxunicode))
property_maps: Dict[str, Set[int]] = defaultdict(set) property_maps: dict[str, set[int]] = defaultdict(set)
def parse_prop_list() -> None: def parse_prop_list() -> None:
@ -118,7 +112,7 @@ def add_word(w: str, c: int) -> None:
category = parts[2] category = parts[2]
s = class_maps.setdefault(category, set()) s = class_maps.setdefault(category, set())
desc = parts[1] desc = parts[1]
codepoints: Union[Tuple[int, ...], Iterable[int]] = (codepoint,) codepoints: Union[tuple[int, ...], Iterable[int]] = (codepoint,)
if first is None: if first is None:
if desc.endswith(', First>'): if desc.endswith(', First>'):
first = codepoint first = codepoint
@ -159,7 +153,7 @@ def add_word(w: str, c: int) -> None:
word_search_map['diamond'] |= word_search_map['gem'] word_search_map['diamond'] |= word_search_map['gem']
def parse_range_spec(spec: str) -> Set[int]: def parse_range_spec(spec: str) -> set[int]:
spec = spec.strip() spec = spec.strip()
if '..' in spec: if '..' in spec:
chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.')))) chars_ = tuple(map(lambda x: int(x, 16), filter(None, spec.split('.'))))
@ -169,17 +163,17 @@ def parse_range_spec(spec: str) -> Set[int]:
return chars return chars
def split_two(line: str) -> Tuple[Set[int], str]: def split_two(line: str) -> tuple[set[int], str]:
spec, rest = line.split(';', 1) spec, rest = line.split(';', 1)
spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip() spec, rest = spec.strip(), rest.strip().split(' ', 1)[0].strip()
return parse_range_spec(spec), rest return parse_range_spec(spec), rest
all_emoji: Set[int] = set() all_emoji: set[int] = set()
emoji_presentation_bases: Set[int] = set() emoji_presentation_bases: set[int] = set()
narrow_emoji: Set[int] = set() narrow_emoji: set[int] = set()
wide_emoji: Set[int] = set() wide_emoji: set[int] = set()
flags: Dict[int, List[int]] = {} flags: dict[int, list[int]] = {}
def parse_basic_emoji(spec: str) -> None: def parse_basic_emoji(spec: str) -> None:
@ -243,13 +237,13 @@ def parse_emoji() -> None:
parse_emoji_modifier_sequence(data) parse_emoji_modifier_sequence(data)
doublewidth: Set[int] = set() doublewidth: set[int] = set()
ambiguous: Set[int] = set() ambiguous: set[int] = set()
def parse_eaw() -> None: def parse_eaw() -> None:
global doublewidth, ambiguous global doublewidth, ambiguous
seen: Set[int] = set() seen: set[int] = set()
for line in get_data('ucd/EastAsianWidth.txt'): for line in get_data('ucd/EastAsianWidth.txt'):
chars, eaw = split_two(line) chars, eaw = split_two(line)
if eaw == 'A': if eaw == 'A':
@ -265,7 +259,7 @@ def parse_eaw() -> None:
doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen doublewidth |= set(range(0x30000, 0x3FFFD + 1)) - seen
def get_ranges(items: List[int]) -> Generator[Union[int, Tuple[int, int]], None, None]: def get_ranges(items: list[int]) -> Generator[Union[int, tuple[int, int]], None, None]:
items.sort() items.sort()
for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]): for k, g in groupby(enumerate(items), lambda m: m[0]-m[1]):
group = tuple(map(itemgetter(1), g)) group = tuple(map(itemgetter(1), g))
@ -276,7 +270,7 @@ def get_ranges(items: List[int]) -> Generator[Union[int, Tuple[int, int]], None,
yield a, b yield a, b
def write_case(spec: Union[Tuple[int, ...], int], p: Callable[..., None], for_go: bool = False) -> None: def write_case(spec: Union[tuple[int, ...], int], p: Callable[..., None], for_go: bool = False) -> None:
if isinstance(spec, tuple): if isinstance(spec, tuple):
if for_go: if for_go:
v = ', '.join(f'0x{x:x}' for x in range(spec[0], spec[1] + 1)) v = ', '.join(f'0x{x:x}' for x in range(spec[0], spec[1] + 1))
@ -332,13 +326,13 @@ def category_test(
classes: Iterable[str], classes: Iterable[str],
comment: str, comment: str,
use_static: bool = False, use_static: bool = False,
extra_chars: Union[FrozenSet[int], Set[int]] = frozenset(), extra_chars: Union[frozenset[int], set[int]] = frozenset(),
exclude: Union[Set[int], FrozenSet[int]] = frozenset(), exclude: Union[set[int], frozenset[int]] = frozenset(),
least_check_return: Optional[str] = None, least_check_return: Optional[str] = None,
ascii_range: Optional[str] = None ascii_range: Optional[str] = None
) -> None: ) -> None:
static = 'static inline ' if use_static else '' static = 'static inline ' if use_static else ''
chars: Set[int] = set() chars: set[int] = set()
for c in classes: for c in classes:
chars |= class_maps[c] chars |= class_maps[c]
chars |= extra_chars chars |= extra_chars
@ -358,7 +352,7 @@ def category_test(
p('\treturn false;\n}\n') p('\treturn false;\n}\n')
def codepoint_to_mark_map(p: Callable[..., None], mark_map: List[int]) -> Dict[int, int]: def codepoint_to_mark_map(p: Callable[..., None], mark_map: list[int]) -> dict[int, int]:
p('\tswitch(c) { // {{{') p('\tswitch(c) { // {{{')
rmap = {c: m for m, c in enumerate(mark_map)} rmap = {c: m for m, c in enumerate(mark_map)}
for spec in get_ranges(mark_map): for spec in get_ranges(mark_map):
@ -374,7 +368,7 @@ def codepoint_to_mark_map(p: Callable[..., None], mark_map: List[int]) -> Dict[i
def classes_to_regex(classes: Iterable[str], exclude: str = '', for_go: bool = True) -> Iterable[str]: def classes_to_regex(classes: Iterable[str], exclude: str = '', for_go: bool = True) -> Iterable[str]:
chars: Set[int] = set() chars: set[int] = set()
for c in classes: for c in classes:
chars |= class_maps[c] chars |= class_maps[c]
for x in map(ord, exclude): for x in map(ord, exclude):
@ -451,7 +445,7 @@ def gen_ucd() -> None:
def gen_names() -> None: def gen_names() -> None:
aliases_map: Dict[int, Set[str]] = {} aliases_map: dict[int, set[str]] = {}
for word, codepoints in word_search_map.items(): for word, codepoints in word_search_map.items():
for cp in codepoints: for cp in codepoints:
aliases_map.setdefault(cp, set()).add(word) aliases_map.setdefault(cp, set()).add(word)
@ -470,10 +464,10 @@ def gen_names() -> None:
def gen_wcwidth() -> None: def gen_wcwidth() -> None:
seen: Set[int] = set() seen: set[int] = set()
non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs'] non_printing = class_maps['Cc'] | class_maps['Cf'] | class_maps['Cs']
def add(p: Callable[..., None], comment: str, chars_: Union[Set[int], FrozenSet[int]], ret: int, for_go: bool = False) -> None: def add(p: Callable[..., None], comment: str, chars_: Union[set[int], frozenset[int]], ret: int, for_go: bool = False) -> None:
chars = chars_ - seen chars = chars_ - seen
seen.update(chars) seen.update(chars)
p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{') p(f'\t\t// {comment} ({len(chars)} codepoints)' + ' {{' '{')
@ -582,7 +576,7 @@ def print_range() -> None:
subprocess.check_call(['gofmt', '-w', '-s', go_file]) subprocess.check_call(['gofmt', '-w', '-s', go_file])
def main(args: List[str]=sys.argv) -> None: def main(args: list[str]=sys.argv) -> None:
parse_ucd() parse_ucd()
parse_prop_list() parse_prop_list()
parse_emoji() parse_emoji()

View file

@ -592,7 +592,7 @@ def test_bracketed_paste_sanitizer(self):
for x in ('\x1b[201~ab\x9b201~cd', '\x1b[201\x1b[201~~ab'): # ]]] for x in ('\x1b[201~ab\x9b201~cd', '\x1b[201\x1b[201~~ab'): # ]]]
q = sanitize_for_bracketed_paste(x.encode('utf-8')) q = sanitize_for_bracketed_paste(x.encode('utf-8'))
self.assertNotIn(b'\x1b[201~', q) self.assertNotIn(b'\x1b[201~', q)
self.assertNotIn('\x9b201~'.encode('utf-8'), q) self.assertNotIn('\x9b201~'.encode(), q)
self.assertIn(b'ab', q) self.assertIn(b'ab', q)
def test_expand_ansi_c_escapes(self): def test_expand_ansi_c_escapes(self):

View file

@ -9,6 +9,7 @@
import sys import sys
import time import time
import unittest import unittest
from collections.abc import Generator, Iterator, Sequence
from contextlib import contextmanager from contextlib import contextmanager
from functools import lru_cache from functools import lru_cache
from tempfile import TemporaryDirectory from tempfile import TemporaryDirectory
@ -16,15 +17,8 @@
from typing import ( from typing import (
Any, Any,
Callable, Callable,
Dict,
Generator,
Iterator,
List,
NoReturn, NoReturn,
Optional, Optional,
Sequence,
Set,
Tuple,
) )
from . import BaseTest from . import BaseTest
@ -68,7 +62,7 @@ def find_all_tests(package: str = '', excludes: Sequence[str] = ('main', 'gr'))
def filter_tests(suite: unittest.TestSuite, test_ok: Callable[[unittest.TestCase], bool]) -> unittest.TestSuite: def filter_tests(suite: unittest.TestSuite, test_ok: Callable[[unittest.TestCase], bool]) -> unittest.TestSuite:
ans = unittest.TestSuite() ans = unittest.TestSuite()
added: Set[unittest.TestCase] = set() added: set[unittest.TestCase] = set()
for test in itertests(suite): for test in itertests(suite):
if test_ok(test) and test not in added: if test_ok(test) and test not in added:
ans.addTest(test) ans.addTest(test)
@ -124,8 +118,8 @@ def run_cli(suite: unittest.TestSuite, verbosity: int = 4) -> bool:
return result.wasSuccessful() return result.wasSuccessful()
def find_testable_go_packages() -> Tuple[Set[str], Dict[str, List[str]]]: def find_testable_go_packages() -> tuple[set[str], dict[str, list[str]]]:
test_functions: Dict[str, List[str]] = {} test_functions: dict[str, list[str]] = {}
ans = set() ans = set()
base = os.getcwd() base = os.getcwd()
pat = re.compile(r'^func Test([A-Z]\w+)', re.MULTILINE) pat = re.compile(r'^func Test([A-Z]\w+)', re.MULTILINE)
@ -148,7 +142,7 @@ def go_exe() -> str:
class GoProc(Thread): class GoProc(Thread):
def __init__(self, cmd: List[str]): def __init__(self, cmd: list[str]):
super().__init__(name='GoProc') super().__init__(name='GoProc')
from kitty.constants import kitty_exe from kitty.constants import kitty_exe
env = os.environ.copy() env = os.environ.copy()
@ -182,7 +176,7 @@ def wait(self, timeout=None) -> None:
return self.stdout.decode('utf-8', 'replace'), self.proc.returncode return self.stdout.decode('utf-8', 'replace'), self.proc.returncode
def run_go(packages: Set[str], names: str) -> GoProc: def run_go(packages: set[str], names: str) -> GoProc:
go = go_exe() go = go_exe()
go_pkg_args = [f'kitty/{x}' for x in packages] go_pkg_args = [f'kitty/{x}' for x in packages]
cmd = [go, 'test', '-v'] cmd = [go, 'test', '-v']
@ -193,7 +187,7 @@ def run_go(packages: Set[str], names: str) -> GoProc:
def reduce_go_pkgs(module: str, names: Sequence[str]) -> Set[str]: def reduce_go_pkgs(module: str, names: Sequence[str]) -> set[str]:
if not go_exe(): if not go_exe():
raise SystemExit('go executable not found, current path: ' + repr(os.environ.get('PATH', ''))) raise SystemExit('go executable not found, current path: ' + repr(os.environ.get('PATH', '')))
go_packages, go_functions = find_testable_go_packages() go_packages, go_functions = find_testable_go_packages()

View file

@ -19,7 +19,7 @@
from . import BaseTest from . import BaseTest
@lru_cache() @lru_cache
def bash_ok(): def bash_ok():
v = shutil.which('bash') v = shutil.which('bash')
if not v: if not v:

View file

@ -46,7 +46,7 @@ def test_ssh_connection_data(self):
def t(cmdline, binary='ssh', host='main', port=None, identity_file='', extra_args=()): def t(cmdline, binary='ssh', host='main', port=None, identity_file='', extra_args=()):
if identity_file: if identity_file:
identity_file = os.path.abspath(identity_file) identity_file = os.path.abspath(identity_file)
en = set(f'{x[0]}' for x in extra_args) en = {f'{x[0]}' for x in extra_args}
q = get_connection_data(cmdline.split(), extra_args=en) q = get_connection_data(cmdline.split(), extra_args=en)
self.ae(q, SSHConnectionData(binary, host, port, identity_file, extra_args)) self.ae(q, SSHConnectionData(binary, host, port, identity_file, extra_args))
@ -59,7 +59,7 @@ def t(cmdline, binary='ssh', host='main', port=None, identity_file='', extra_arg
self.assertTrue(runtime_dir()) self.assertTrue(runtime_dir())
@property @property
@lru_cache() @lru_cache
def all_possible_sh(self): def all_possible_sh(self):
python = 'python3' if shutil.which('python3') else 'python' python = 'python3' if shutil.which('python3') else 'python'
return tuple(filter(shutil.which, ('dash', 'zsh', 'bash', 'posh', 'sh', python))) return tuple(filter(shutil.which, ('dash', 'zsh', 'bash', 'posh', 'sh', python)))
@ -102,7 +102,7 @@ def touch(p):
self.assertTrue(os.path.exists(f'{remote_home}/{tname}/78/xterm-kitty')) self.assertTrue(os.path.exists(f'{remote_home}/{tname}/78/xterm-kitty'))
self.assertTrue(os.path.exists(f'{remote_home}/{tname}/x/xterm-kitty')) self.assertTrue(os.path.exists(f'{remote_home}/{tname}/x/xterm-kitty'))
for w in ('simple-file', 'a/sfa', 's2'): for w in ('simple-file', 'a/sfa', 's2'):
with open(os.path.join(remote_home, w), 'r') as f: with open(os.path.join(remote_home, w)) as f:
self.ae(f.read(), simple_data) self.ae(f.read(), simple_data)
self.assertFalse(os.path.islink(f.name)) self.assertFalse(os.path.islink(f.name))
self.assertTrue(os.path.lexists(f'{remote_home}/d1/y')) self.assertTrue(os.path.lexists(f'{remote_home}/d1/y'))