More pyugrade to 3.9
This commit is contained in:
parent
a35f7e060b
commit
2b3f2258ff
12 changed files with 88 additions and 110 deletions
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -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 = []
|
||||||
|
|
|
||||||
|
|
@ -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 = {}
|
||||||
|
|
|
||||||
|
|
@ -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())
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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')
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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):
|
||||||
|
|
|
||||||
|
|
@ -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()
|
||||||
|
|
|
||||||
|
|
@ -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:
|
||||||
|
|
|
||||||
|
|
@ -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'))
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue