diff --git a/kittens/runner.py b/kittens/runner.py index 5bf42b70f..b7d214473 100644 --- a/kittens/runner.py +++ b/kittens/runner.py @@ -6,7 +6,6 @@ import importlib import os import sys -from contextlib import suppress from functools import partial aliases = {'url_hints': 'hints'} @@ -99,9 +98,11 @@ def run_kitten(kitten, run_name='__main__'): original_kitten_name = kitten kitten = resolved_kitten(kitten) set_debug(kitten) - with suppress(ImportError): + try: runpy.run_module('kittens.{}.main'.format(kitten), run_name=run_name) return + except ImportError: + pass # Look for a custom kitten if not kitten.endswith('.py'): kitten += '.py' diff --git a/kittens/tui/operations.py b/kittens/tui/operations.py index 2da16dd1f..d585f345f 100644 --- a/kittens/tui/operations.py +++ b/kittens/tui/operations.py @@ -63,8 +63,8 @@ def beep() -> str: return '\a' -def set_window_title(value) -> str: - return ('\033]2;' + value.replace('\033', '').replace('\x9c', '') + '\033\\') +def set_window_title(value: str) -> str: + return '\033]2;' + value.replace('\033', '').replace('\x9c', '') + '\033\\' def set_line_wrapping(yes_or_no: bool) -> str: @@ -134,7 +134,7 @@ def faint(text) -> str: return colored(text, 'black', True) -def styled(text, fg=None, bg=None, fg_intense=False, bg_intense=False, italic=None, bold=None, underline=None, underline_color=None, reverse=None) -> str: +def styled(text: str, fg=None, bg=None, fg_intense=False, bg_intense=False, italic=None, bold=None, underline=None, underline_color=None, reverse=None) -> str: start, end = [], [] if fg is not None: start.append(color_code(fg, fg_intense)) @@ -167,7 +167,7 @@ def styled(text, fg=None, bg=None, fg_intense=False, bg_intense=False, italic=No return '\033[{}m{}\033[{}m'.format(';'.join(start), text, ';'.join(end)) -def serialize_gr_command(cmd, payload=None): +def serialize_gr_command(cmd, payload=None) -> bytes: cmd = ','.join('{}={}'.format(k, v) for k, v in cmd.items()) ans: List[bytes] = [] w = ans.append @@ -180,11 +180,11 @@ def serialize_gr_command(cmd, payload=None): def gr_command(cmd, payload=None) -> str: - return serialize_gr_command(cmd, payload) + return serialize_gr_command(cmd, payload).decode('ascii') def clear_images_on_screen(delete_data=False) -> str: - return serialize_gr_command({'a': 'd', 'd': 'A' if delete_data else 'a'}) + return serialize_gr_command({'a': 'd', 'd': 'A' if delete_data else 'a'}).decode('ascii') def init_state(alternate_screen=True): @@ -255,8 +255,9 @@ def write_to_clipboard(data, use_primary=False) -> str: from base64 import standard_b64encode fmt = 'p' if use_primary else 'c' - def esc(chunk): + def esc(chunk: str) -> str: return '\x1b]52;{};{}\x07'.format(fmt, chunk) + ans = esc('!') # clear clipboard buffer for chunk in (data[i:i+512] for i in range(0, len(data), 512)): chunk = standard_b64encode(chunk).decode('ascii') diff --git a/kittens/unicode_input/main.py b/kittens/unicode_input/main.py index ee2d38b61..bc9914936 100644 --- a/kittens/unicode_input/main.py +++ b/kittens/unicode_input/main.py @@ -260,11 +260,12 @@ class Table: self.layout_dirty = True -def is_index(w): - with suppress(Exception): +def is_index(w: str) -> bool: + try: int(w.lstrip(INDEX_CHAR), 16) return True - return False + except Exception: + return False class UnicodeInput(Handler): diff --git a/kitty/cli.py b/kitty/cli.py index 72f279846..22a40338a 100644 --- a/kitty/cli.py +++ b/kitty/cli.py @@ -674,7 +674,8 @@ type=bool-set appname=appname, config_help=CONFIG_HELP.format(appname=appname, conf_name=appname) )) - return getattr(options_spec, 'ans') + ans: str = getattr(options_spec, 'ans') + return ans def options_for_completion() -> OptionSpecSeq: @@ -703,7 +704,7 @@ def parse_args( usage: Optional[str] = None, message: Optional[str] = None, appname: Optional[str] = None, - result_class: Type[T] = None, + result_class: Optional[Type[T]] = None, ) -> Tuple[T, List[str]]: options = parse_option_spec(ospec()) seq, disabled = options diff --git a/kitty/conf/utils.py b/kitty/conf/utils.py index 281a4546d..e0d74442e 100644 --- a/kitty/conf/utils.py +++ b/kitty/conf/utils.py @@ -6,7 +6,10 @@ import os import re import shlex from collections import namedtuple -from typing import Callable, FrozenSet, List, Optional, Union, Dict, Any, Iterator, Type +from typing import ( + Any, Callable, Dict, FrozenSet, Iterator, List, Optional, Sequence, Tuple, + Type, Union +) from ..rgb import Color, to_color as as_color from ..utils import log_error @@ -56,12 +59,13 @@ def to_cmdline(x: str) -> List[str]: def python_string(text: str) -> str: import ast - return ast.literal_eval("'''" + text.replace("'''", "'\\''") + "'''") + ans: str = ast.literal_eval("'''" + text.replace("'''", "'\\''") + "'''") + return ans -def choices(*choices) -> Callable[[str], str]: - defval: str = choices[0] - uc: FrozenSet[str] = frozenset(choices) +def choices(*choices: str) -> Callable[[str], str]: + defval = choices[0] + uc = frozenset(choices) def choice(x: str) -> str: x = x.lower() @@ -199,13 +203,13 @@ def create_options_class(all_keys: Iterator[str]) -> Type: return ans -def merge_dicts(defaults, newvals): +def merge_dicts(defaults: Dict, newvals: Dict) -> Dict: ans = defaults.copy() ans.update(newvals) return ans -def resolve_config(SYSTEM_CONF, defconf, config_files_on_cmd_line): +def resolve_config(SYSTEM_CONF: str, defconf: str, config_files_on_cmd_line: Sequence[str]): if config_files_on_cmd_line: if 'NONE' not in config_files_on_cmd_line: yield SYSTEM_CONF @@ -217,9 +221,14 @@ def resolve_config(SYSTEM_CONF, defconf, config_files_on_cmd_line): def load_config( - Options, defaults, parse_config, merge_configs, *paths, overrides=None + Options: Type, + defaults: Any, + parse_config: Callable[[Iterator[str]], Dict[str, Any]], + merge_configs: Callable[[Dict, Dict], Dict], + *paths: str, + overrides: Optional[Iterator[str]] = None ): - ans = defaults._asdict() + ans: Dict = defaults._asdict() for path in paths: if not path: continue @@ -235,7 +244,7 @@ def load_config( return Options(ans) -def init_config(default_config_lines, parse_config): +def init_config(default_config_lines: Iterator[str], parse_config: Callable): defaults = parse_config(default_config_lines, check_keys=False) Options = create_options_class(defaults.keys()) defaults = Options(defaults) @@ -260,7 +269,7 @@ def key_func(): return func_with_args, ans -def parse_kittens_shortcut(sc): +def parse_kittens_shortcut(sc: str) -> Tuple[Optional[int], str, bool]: from ..key_encoding import config_key_map, config_mod_map, text_match if sc.endswith('+'): parts = list(filter(None, sc.rstrip('+').split('+') + ['+'])) @@ -282,16 +291,17 @@ def parse_kittens_shortcut(sc): tkey = text_match(rkey) if tkey is None: rkey = rkey.upper() - rkey = config_key_map.get(rkey) - if rkey is None: + q = config_key_map.get(rkey) + if q is None: raise ValueError('Unknown shortcut key: {}'.format(sc)) + rkey = q else: is_text = True rkey = tkey return mods, rkey, is_text -def parse_kittens_func_args(action, args_funcs): +def parse_kittens_func_args(action: str, args_funcs: Dict[str, Callable]) -> Tuple[str, Tuple[str, ...]]: parts = action.strip().split(' ', 1) func = parts[0] if len(parts) == 1: @@ -317,10 +327,12 @@ def parse_kittens_func_args(action, args_funcs): return func, tuple(args) -def parse_kittens_key(val, funcs_with_args): +def parse_kittens_key( + val: str, funcs_with_args: Dict[str, Callable] +) -> Optional[Tuple[Tuple[str, Tuple[str, ...]], str, Optional[int], bool]]: sc, action = val.partition(' ')[::2] if not sc or not action: - return + return None mods, key, is_text = parse_kittens_shortcut(sc) - action = parse_kittens_func_args(action, funcs_with_args) - return action, key, mods, is_text + ans = parse_kittens_func_args(action, funcs_with_args) + return ans, key, mods, is_text diff --git a/kitty/config.py b/kitty/config.py index 0a923b4f7..e8a4f9620 100644 --- a/kitty/config.py +++ b/kitty/config.py @@ -483,7 +483,7 @@ def handle_symbol_map(key, val, ans): class FontFeature(str): def __new__(cls, name, parsed): - ans = str.__new__(cls, name) # type: ignore + ans = str.__new__(cls, name) ans.parsed = parsed return ans @@ -624,7 +624,7 @@ actions = frozenset(all_key_actions) | frozenset( no_op_actions = frozenset({'noop', 'no-op', 'no_op'}) -def merge_configs(defaults, vals): +def merge_configs(defaults: Dict, vals: Dict) -> Dict: ans = {} for k, v in defaults.items(): if isinstance(v, dict): @@ -777,7 +777,7 @@ def finalize_keys(opts: OptionsStub) -> None: opts.sequence_map = sequence_map -def load_config(*paths: Tuple[str], overrides: Optional[Iterator[str]] = None, accumulate_bad_lines: Optional[List[BadLine]] = None) -> OptionsStub: +def load_config(*paths: 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) diff --git a/kitty/launch.py b/kitty/launch.py index 4bed1bb46..fa8c7439a 100644 --- a/kitty/launch.py +++ b/kitty/launch.py @@ -18,7 +18,7 @@ from .tabs import Tab try: from typing import TypedDict except ImportError: - TypedDict = Dict[str, Any] # type: ignore + TypedDict = Dict[str, Any] @lru_cache(maxsize=2) @@ -162,7 +162,7 @@ def get_env(opts: LaunchCLIOptions, active_child: Child) -> Dict[str, str]: def tab_for_window(boss: Boss, opts: LaunchCLIOptions, target_tab: Optional[Tab] = None) -> Tab: if opts.type == 'tab': tm = boss.active_tab_manager - tab = tm.new_tab(empty_tab=True, location=opts.location) + tab: Tab = tm.new_tab(empty_tab=True, location=opts.location) if opts.tab_title: tab.set_title(opts.tab_title) elif opts.type == 'os-window': @@ -252,7 +252,7 @@ def launch(boss: Boss, opts: LaunchCLIOptions, args: List[str], target_tab: Opti func(kw['stdin']) else: tab = tab_for_window(boss, opts, target_tab) - new_window = tab.new_window(env=env or None, **kw) + new_window: Window = tab.new_window(env=env or None, **kw) if opts.keep_focus and active: boss.set_active_window(active, switch_os_window_if_needed=True) return new_window diff --git a/kitty/layout.py b/kitty/layout.py index 8e4c93bc5..55ac8df44 100644 --- a/kitty/layout.py +++ b/kitty/layout.py @@ -466,7 +466,7 @@ class Layout: # {{{ def window_independent_borders(self, windows, active_windows): return - yield + yield # type:ignore def minimal_borders(self, windows, active_window, needs_borders_map): for w in windows: diff --git a/kitty/rgb.py b/kitty/rgb.py index d3de81a99..edfb40be4 100644 --- a/kitty/rgb.py +++ b/kitty/rgb.py @@ -3,11 +3,14 @@ # License: GPL v3 Copyright: 2017, Kovid Goyal import re -from collections import namedtuple from contextlib import suppress -from typing import Optional +from typing import Optional, NamedTuple -Color = namedtuple('Color', 'red green blue') + +class Color(NamedTuple): + red: int + green: int + blue: int def alpha_blend_channel(top_color: int, bottom_color: int, alpha: float) -> int: diff --git a/kitty/utils.py b/kitty/utils.py index 528c2cd96..4de5fd7de 100644 --- a/kitty/utils.py +++ b/kitty/utils.py @@ -468,17 +468,17 @@ def func_name(f): def resolved_shell(opts: Optional[Options] = None) -> List[str]: - ans = getattr(opts, 'shell', '.') - if ans == '.': + q: str = getattr(opts, 'shell', '.') + if q == '.': ans = [shell_path] else: import shlex - ans = shlex.split(ans) + ans = shlex.split(q) return ans def read_shell_environment(opts: Optional[Options] = None) -> Dict[str, str]: - ans = getattr(read_shell_environment, 'ans', None) + ans: Optional[Dict[str, str]] = getattr(read_shell_environment, 'ans', None) if ans is None: from .child import openpty, remove_blocking ans = {} @@ -506,7 +506,7 @@ def read_shell_environment(opts: Optional[Options] = None) -> Dict[str, str]: raw += stdout.read() if ret is not None: break - if p.returncode is None: + if cast(Optional[int], p.returncode) is None: log_error('Timed out waiting for shell to quit while reading shell environment') p.kill() elif p.returncode == 0: diff --git a/setup.cfg b/setup.cfg index 59ad1dbf9..e5e049b03 100644 --- a/setup.cfg +++ b/setup.cfg @@ -15,9 +15,11 @@ multi_line_output = 5 [mypy] files = kitty,kittens,glfw/glfw.py,*.py - -[mypy-kitty.conf.*] -check_untyped_defs = True - -[mypy-kitty.cli] -check_untyped_defs = True +no_implicit_optional = True +sqlite_cache = True +cache_fine_grained = True +warn_redundant_casts = True +warn_unused_ignores = True +warn_return_any = True +warn_unreachable = True +# check_untyped_defs = True