From a76a163db5816872262ecafc92226013319ccb4c Mon Sep 17 00:00:00 2001 From: Kovid Goyal Date: Thu, 5 Mar 2020 18:17:21 +0530 Subject: [PATCH] kitty.config is typed --- kitty/conf/definition.py | 2 ++ kitty/config.py | 71 ++++++++++++++++++++++----------------- kitty/fast_data_types.pyi | 8 +++++ kitty/options_stub.py | 3 +- setup.cfg | 2 -- 5 files changed, 52 insertions(+), 34 deletions(-) diff --git a/kitty/conf/definition.py b/kitty/conf/definition.py index 958030b06..7751fb26c 100644 --- a/kitty/conf/definition.py +++ b/kitty/conf/definition.py @@ -326,6 +326,8 @@ def as_type_stub( ans.insert(0, 'import {}'.format(mod)) for field_name, type_def in extra_fields: ans.append(' {}: {}'.format(field_name, type_def)) + ans.append(' def __iter__(self): pass') + ans.append(' def __len__(self): pass') return '\n'.join(ans) diff --git a/kitty/config.py b/kitty/config.py index 473265740..0a923b4f7 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -9,12 +9,15 @@ import sys from collections import namedtuple from contextlib import contextmanager, suppress from functools import partial -from typing import Type +from typing import ( + TYPE_CHECKING, Any, Dict, Iterator, List, Optional, Sequence, Tuple, Type, + cast +) from . import fast_data_types as defines from .conf.definition import as_conf_file, config_lines from .conf.utils import ( - init_config, key_func, load_config as _load_config, merge_dicts, + BadLine, init_config, key_func, load_config as _load_config, merge_dicts, parse_config_base, python_string, to_bool, to_cmdline ) from .config_data import all_options, parse_mods, type_convert @@ -23,6 +26,10 @@ from .key_names import get_key_name_lookup, key_name_aliases from .options_stub import Options as OptionsStub from .utils import log_error +if TYPE_CHECKING: + from .options_stub import SequenceMap, KeyMap + SequenceMap, KeyMap + def parse_shortcut(sc): parts = sc.split('+') @@ -121,19 +128,18 @@ def float_parse(func, rest): @func_with_args('change_font_size') -def parse_change_font_size(func, rest): +def parse_change_font_size(func: str, rest: str) -> Tuple[str, Tuple[bool, Optional[str], float]]: vals = rest.strip().split(maxsplit=1) if len(vals) != 2: log_error('Invalid change_font_size specification: {}, treating it as default'.format(rest)) - args = [True, None, 0] - else: - args = [vals[0].lower() == 'all', None, 0] - amt = vals[1] - if amt[0] in '+-': - args[1] = amt[0] - amt = amt[1:] - args[2] = float(amt.strip()) - return func, args + return func, (True, None, 0) + c_all = vals[0].lower() == 'all' + sign: Optional[str] = None + amt = vals[1] + if amt[0] in '+-': + sign = amt[0] + amt = amt[1:] + return func, (c_all, sign, float(amt.strip())) @func_with_args('clear_terminal') @@ -336,7 +342,7 @@ class KeyDefinition: self.trigger = defines.resolve_key_mods(kitty_mod, self.trigger[0]), self.trigger[1], self.trigger[2] self.rest = tuple((defines.resolve_key_mods(kitty_mod, mods), is_native, key) for mods, is_native, key in self.rest) - def resolve_kitten_aliases(self, aliases): + def resolve_kitten_aliases(self, aliases: Dict[str, Sequence[str]]): if not self.action.args: return kitten = self.action.args[0] @@ -363,7 +369,7 @@ def parse_key(val, key_definitions): is_sequence = sequence_sep in sc if is_sequence: trigger = None - rest = [] + restl: List[Tuple[int, bool, int]] = [] for part in sc.split(sequence_sep): mods, is_native, key = parse_shortcut(part) if key is None: @@ -373,8 +379,8 @@ def parse_key(val, key_definitions): if trigger is None: trigger = mods, is_native, key else: - rest.append((mods, is_native, key)) - rest = tuple(rest) + restl.append((mods, is_native, key)) + rest = tuple(restl) else: mods, is_native, key = parse_shortcut(sc) if key is None: @@ -390,7 +396,8 @@ def parse_key(val, key_definitions): if paction is not None: all_key_actions.add(paction.func) if is_sequence: - key_definitions.append(KeyDefinition(True, paction, trigger[0], trigger[1], trigger[2], rest)) + if trigger is not None: + key_definitions.append(KeyDefinition(True, paction, trigger[0], trigger[1], trigger[2], rest)) else: key_definitions.append(KeyDefinition(False, paction, mods, is_native, key)) @@ -476,7 +483,7 @@ def handle_symbol_map(key, val, ans): class FontFeature(str): def __new__(cls, name, parsed): - ans = str.__new__(cls, name) + ans = str.__new__(cls, name) # type: ignore ans.parsed = parsed return ans @@ -581,12 +588,14 @@ def option_names_for_completion(): yield from special_handlers -def parse_config(lines, check_keys=True, accumulate_bad_lines=None): - ans = {'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], 'env': {}, 'kitten_aliases': {}, 'font_features': {}} +def parse_config(lines: Iterator[str], check_keys=True, accumulate_bad_lines: Optional[List[BadLine]] = None): + ans: Dict[str, Any] = { + 'symbol_map': {}, 'keymap': {}, 'sequence_map': {}, 'key_definitions': [], + 'env': {}, 'kitten_aliases': {}, 'font_features': {} + } + defs: Optional[OptionsStub] = None if check_keys: defs = defaults - else: - defs = None parse_config_base( lines, @@ -659,7 +668,7 @@ def atomic_save(data, path): @contextmanager def cached_values_for(name): cached_path = os.path.join(cache_dir(), name + '.json') - cached_values = {} + cached_values: Dict = {} try: with open(cached_path, 'rb') as f: cached_values.update(json.loads(f.read().decode('utf-8'))) @@ -732,20 +741,20 @@ def prepare_config_file_for_editing(): return defconf -def finalize_keys(opts): - defns = [] - for d in opts.key_definitions: +def finalize_keys(opts: OptionsStub) -> None: + defns: List[KeyDefinition] = [] + for d in getattr(opts, 'key_definitions'): if d is None: # clear_all_shortcuts defns = [] else: defns.append(d) - kitten_aliases = opts.kitten_aliases + kitten_aliases: List[Dict[str, Sequence[str]]] = getattr(opts, 'kitten_aliases') for d in defns: d.resolve(opts.kitty_mod) if kitten_aliases and d.action.func == 'kitten': d.resolve_kitten_aliases(kitten_aliases) - keymap = {} - sequence_map = {} + keymap: KeyMap = {} + sequence_map: SequenceMap = {} for defn in defns: is_no_op = defn.action.func in no_op_actions @@ -768,11 +777,11 @@ def finalize_keys(opts): opts.sequence_map = sequence_map -def load_config(*paths, overrides=None, accumulate_bad_lines=None) -> OptionsStub: +def load_config(*paths: Tuple[str], overrides: Optional[Iterator[str]] = None, accumulate_bad_lines: Optional[List[BadLine]] = None) -> OptionsStub: parser = parse_config if accumulate_bad_lines is not None: parser = partial(parse_config, accumulate_bad_lines=accumulate_bad_lines) - opts = _load_config(Options, defaults, parser, merge_configs, *paths, overrides=overrides) + opts = cast(OptionsStub, _load_config(Options, defaults, parser, merge_configs, *paths, overrides=overrides)) finalize_keys(opts) if opts.background_opacity < 1.0 and opts.macos_titlebar_color: log_error('Cannot use both macos_titlebar_color and background_opacity') diff --git a/kitty/fast_data_types.pyi b/kitty/fast_data_types.pyi index 023825844..1a353c326 100644 --- a/kitty/fast_data_types.pyi +++ b/kitty/fast_data_types.pyi @@ -481,6 +481,14 @@ def set_options( pass +def resolve_key_mods(kitty_mod: int, mods: int) -> int: + pass + + +def parse_font_feature(str) -> bytes: + pass + + def set_default_window_icon(data: bytes, width: int, height: int) -> None: pass diff --git a/kitty/options_stub.py b/kitty/options_stub.py index 47f289fe6..49a73b0f5 100644 --- a/kitty/options_stub.py +++ b/kitty/options_stub.py @@ -19,10 +19,11 @@ def generate_stub(): 'from kitty.config import KeyAction', 'KeySpec = typing.Tuple[int, bool, int]', 'KeyMap = typing.Dict[KeySpec, KeyAction]', + 'SequenceMap = typing.Dict[KeySpec, KeyMap]', ), extra_fields=( ('keymap', 'KeyMap'), - ('sequence_map', 'typing.Dict[KeySpec, KeyMap]'), + ('sequence_map', 'SequenceMap'), ) ) save_type_stub(text, __file__) diff --git a/setup.cfg b/setup.cfg index 0ea40cec2..59ad1dbf9 100644 --- a/setup.cfg +++ b/setup.cfg @@ -18,8 +18,6 @@ files = kitty,kittens,glfw/glfw.py,*.py [mypy-kitty.conf.*] check_untyped_defs = True -follow_imports = silent [mypy-kitty.cli] check_untyped_defs = True -follow_imports = silent