diff options
-rw-r--r-- | poezio/bookmarks.py | 23 | ||||
-rw-r--r-- | poezio/colors.py | 22 | ||||
-rw-r--r-- | poezio/decorators.py | 43 | ||||
-rw-r--r-- | poezio/tabs/confirmtab.py | 6 | ||||
-rw-r--r-- | poezio/tabs/listtab.py | 6 | ||||
-rw-r--r-- | poezio/tabs/muctab.py | 65 | ||||
-rw-r--r-- | poezio/tabs/rostertab.py | 6 | ||||
-rwxr-xr-x | poezio/theming.py | 6 | ||||
-rw-r--r-- | poezio/windows/base_wins.py | 10 | ||||
-rw-r--r-- | poezio/windows/funcs.py | 17 | ||||
-rw-r--r-- | poezio/windows/info_bar.py | 9 |
11 files changed, 109 insertions, 104 deletions
diff --git a/poezio/bookmarks.py b/poezio/bookmarks.py index f6f22363..0406de94 100644 --- a/poezio/bookmarks.py +++ b/poezio/bookmarks.py @@ -30,7 +30,7 @@ Adding a remote bookmark: import functools import logging -from typing import Optional, List +from typing import Optional, List, Union from slixmpp import JID from slixmpp.plugins.xep_0048 import Bookmarks, Conference, URL @@ -130,7 +130,7 @@ class Bookmark: class BookmarkList: def __init__(self): - self.bookmarks = [] + self.bookmarks = [] # type: List[Bookmark] preferred = config.get('use_bookmarks_method').lower() if preferred not in ('pep', 'privatexml'): preferred = 'privatexml' @@ -140,15 +140,16 @@ class BookmarkList: 'pep': False, } - def __getitem__(self, key): + def __getitem__(self, key: Union[str, JID, int]) -> Optional[Bookmark]: if isinstance(key, (str, JID)): for i in self.bookmarks: if key == i.jid: return i - else: + elif isinstance(key, int): return self.bookmarks[key] + return None - def __in__(self, key): + def __in__(self, key) -> bool: if isinstance(key, (str, JID)): for bookmark in self.bookmarks: if bookmark.jid == key: @@ -168,16 +169,16 @@ class BookmarkList: def __iter__(self): return iter(self.bookmarks) - def local(self): + def local(self) -> List[Bookmark]: return [bm for bm in self.bookmarks if bm.method == 'local'] - def remote(self): + def remote(self) -> List[Bookmark]: return [bm for bm in self.bookmarks if bm.method == 'remote'] - def set(self, new): + def set(self, new: List[Bookmark]): self.bookmarks = new - def append(self, bookmark): + def append(self, bookmark: Bookmark): bookmark_exists = self[bookmark.jid] if not bookmark_exists: self.bookmarks.append(bookmark) @@ -185,7 +186,7 @@ class BookmarkList: self.bookmarks.remove(bookmark_exists) self.bookmarks.append(bookmark) - def set_bookmarks_method(self, value): + def set_bookmarks_method(self, value: str): if self.available_storage.get(value): self.preferred = value config.set_and_save('use_bookmarks_method', value) @@ -306,7 +307,7 @@ class BookmarkList: self.append(b) -def stanza_storage(bookmarks): +def stanza_storage(bookmarks: BookmarkList) -> Bookmarks: """Generate a <storage/> stanza with the conference elements.""" storage = Bookmarks() for b in (b for b in bookmarks if b.method == 'remote'): diff --git a/poezio/colors.py b/poezio/colors.py index 2e90b9b0..6bbbb12e 100644 --- a/poezio/colors.py +++ b/poezio/colors.py @@ -1,14 +1,17 @@ +from typing import Tuple, Dict, List import curses import hashlib import math +Palette = Dict[float, int] + # BT.601 (YCbCr) constants, see XEP-0392 K_R = 0.299 K_G = 0.587 K_B = 1 - K_R - K_G -def ncurses_color_to_rgb(color): +def ncurses_color_to_rgb(color: int) -> Tuple[float, float, float]: if color <= 15: try: (r, g, b) = curses.color_content(color) @@ -30,15 +33,16 @@ def ncurses_color_to_rgb(color): return r / 5, g / 5, b / 5 -def rgb_to_ycbcr(r, g, b): +def rgb_to_ycbcr(r: float, g: float, b: float) -> Tuple[float, float, float]: y = K_R * r + K_G * g + K_B * b cr = (r - y) / (1 - K_R) / 2 cb = (b - y) / (1 - K_B) / 2 return y, cb, cr -def generate_ccg_palette(curses_palette, reference_y): - cbcr_palette = {} +def generate_ccg_palette(curses_palette: List[int], + reference_y: float) -> Palette: + cbcr_palette = {} # type: Dict[float, Tuple[float, int]] for curses_color in curses_palette: r, g, b = ncurses_color_to_rgb(curses_color) # drop grayscale @@ -60,14 +64,14 @@ def generate_ccg_palette(curses_palette, reference_y): } -def text_to_angle(text): +def text_to_angle(text: str) -> float: hf = hashlib.sha1() hf.update(text.encode("utf-8")) hue = int.from_bytes(hf.digest()[:2], "little") return hue / 65535 * math.pi * 2 -def angle_to_cbcr_edge(angle): +def angle_to_cbcr_edge(angle: float) -> Tuple[float, float]: cr = math.sin(angle) cb = math.cos(angle) if abs(cr) > abs(cb): @@ -77,7 +81,7 @@ def angle_to_cbcr_edge(angle): return cb * factor, cr * factor -def cbcr_to_angle(cb, cr): +def cbcr_to_angle(cb: float, cr: float) -> float: magn = math.sqrt(cb**2 + cr**2) if magn > 0: cr /= magn @@ -85,7 +89,7 @@ def cbcr_to_angle(cb, cr): return math.atan2(cr, cb) % (2 * math.pi) -def ccg_palette_lookup(palette, angle): +def ccg_palette_lookup(palette: Palette, angle: float) -> int: # try quick lookup first try: color = palette[round(angle, 2)] @@ -105,6 +109,6 @@ def ccg_palette_lookup(palette, angle): return best -def ccg_text_to_color(palette, text): +def ccg_text_to_color(palette, text: str) -> int: angle = text_to_angle(text) return ccg_palette_lookup(palette, angle) diff --git a/poezio/decorators.py b/poezio/decorators.py index 7823dbaf..bf1c2ebe 100644 --- a/poezio/decorators.py +++ b/poezio/decorators.py @@ -1,6 +1,7 @@ """ Module containing various decorators """ +from typing import Any, Callable, List, Optional from poezio import common @@ -9,7 +10,7 @@ class RefreshWrapper: def __init__(self): self.core = None - def conditional(self, func): + def conditional(self, func: Callable) -> Callable: """ Decorator to refresh the UI if the wrapped function returns True @@ -23,7 +24,7 @@ class RefreshWrapper: return wrap - def always(self, func): + def always(self, func: Callable) -> Callable: """ Decorator that refreshs the UI no matter what after the function """ @@ -36,7 +37,7 @@ class RefreshWrapper: return wrap - def update(self, func): + def update(self, func: Callable) -> Callable: """ Decorator that only updates the screen """ @@ -60,7 +61,7 @@ class CommandArgParser: """ @staticmethod - def raw(func): + def raw(func: Callable) -> Callable: """Just call the function with a single string, which is the original string untouched """ @@ -71,7 +72,7 @@ class CommandArgParser: return wrap @staticmethod - def ignored(func): + def ignored(func: Callable) -> Callable: """ Call the function without any argument """ @@ -82,9 +83,9 @@ class CommandArgParser: return wrap @staticmethod - def quoted(mandatory, + def quoted(mandatory: int, optional=0, - defaults=None, + defaults: Optional[List[Any]] = None, ignore_trailing_arguments=False): """The function receives a list with a number of arguments that is between the numbers `mandatory` and `optional`. @@ -128,31 +129,31 @@ class CommandArgParser: ['un et demi', 'deux', 'trois quatre cinq six'] """ - if defaults is None: - defaults = [] + default_args_outer = defaults or [] - def first(func): - def second(self, args, *a, **kw): - default_args = defaults + def first(func: Callable): + def second(self, args: str, *a, **kw): + default_args = default_args_outer if args and args.strip(): - args = common.shell_split(args) + split_args = common.shell_split(args) else: - args = [] - if len(args) < mandatory: + split_args = [] + if len(split_args) < mandatory: return func(self, None, *a, **kw) - res, args = args[:mandatory], args[mandatory:] + res, split_args = split_args[:mandatory], split_args[ + mandatory:] if optional == -1: - opt_args = args[:] + opt_args = split_args[:] else: - opt_args = args[:optional] + opt_args = split_args[:optional] if opt_args: res += opt_args - args = args[len(opt_args):] + split_args = split_args[len(opt_args):] default_args = default_args[len(opt_args):] res += default_args - if args and res and not ignore_trailing_arguments: - res[-1] += " " + " ".join(args) + if split_args and res and not ignore_trailing_arguments: + res[-1] += " " + " ".join(split_args) return func(self, res, *a, **kw) return second diff --git a/poezio/tabs/confirmtab.py b/poezio/tabs/confirmtab.py index c76883dd..c13de4a6 100644 --- a/poezio/tabs/confirmtab.py +++ b/poezio/tabs/confirmtab.py @@ -99,10 +99,8 @@ class ConfirmTab(Tab): def on_input(self, key, raw): res = self.input.do_command(key, raw=raw) - if res and not isinstance(self.input, windows.Input): - return True - elif res: - return False + if res: + return not isinstance(self.input, windows.Input) if not raw and key in self.key_func: return self.key_func[key]() diff --git a/poezio/tabs/listtab.py b/poezio/tabs/listtab.py index 6a4da08e..07b3fe05 100644 --- a/poezio/tabs/listtab.py +++ b/poezio/tabs/listtab.py @@ -161,10 +161,8 @@ class ListTab(Tab): def on_input(self, key, raw): res = self.input.do_command(key, raw=raw) - if res and not isinstance(self.input, windows.Input): - return True - elif res: - return False + if res: + return not isinstance(self.input, windows.Input) if not raw and key in self.key_func: return self.key_func[key]() diff --git a/poezio/tabs/muctab.py b/poezio/tabs/muctab.py index 934dc0b1..507a47bd 100644 --- a/poezio/tabs/muctab.py +++ b/poezio/tabs/muctab.py @@ -14,8 +14,9 @@ import os import random import re from datetime import datetime -from typing import Dict, Callable +from typing import Dict, Callable, List, Optional, Union, Set +from slixmpp import JID from poezio.tabs import ChatTab, Tab, SHOW_NAME from poezio import common @@ -56,15 +57,15 @@ class MucTab(ChatTab): # our nick in the MUC self.own_nick = nick # self User object - self.own_user = None + self.own_user = None # type: Optional[User] self.name = jid self.password = password # buffered presences self.presence_buffer = [] # userlist - self.users = [] + self.users = [] # type: List[User] # private conversations - self.privates = [] + self.privates = [] # type: List[Tab] self.topic = '' self.topic_from = '' # Self ping event, so we can cancel it when we leave the room @@ -78,7 +79,7 @@ class MucTab(ChatTab): self.info_header = windows.MucInfoWin() self.input = windows.MessageInput() # List of ignored users - self.ignores = [] + self.ignores = [] # type: List[User] # keys self.register_keys() self.update_keys() @@ -91,12 +92,12 @@ class MucTab(ChatTab): def general_jid(self): return self.name - def check_send_chat_state(self): + def check_send_chat_state(self) -> bool: "If we should send a chat state" return self.joined @property - def last_connection(self): + def last_connection(self) -> Optional[datetime]: last_message = self._text_buffer.last_message if last_message: return last_message.time @@ -135,7 +136,7 @@ class MucTab(ChatTab): show=status.show, seconds=seconds) - def leave_room(self, message): + def leave_room(self, message: str): if self.joined: info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT) char_quit = get_theme().CHAR_QUIT @@ -145,7 +146,7 @@ class MucTab(ChatTab): self.general_jid): color = dump_tuple(get_theme().COLOR_OWN_NICK) else: - color = 3 + color = "3" if message: msg = ('\x19%(color_spec)s}%(spec)s\x19%(info_col)s} ' @@ -179,7 +180,10 @@ class MucTab(ChatTab): muc.leave_groupchat(self.core.xmpp, self.name, self.own_nick, message) - def change_affiliation(self, nick_or_jid, affiliation, reason=''): + def change_affiliation(self, + nick_or_jid: Union[str, JID], + affiliation: str, + reason=''): """ Change the affiliation of a nick or JID """ @@ -215,7 +219,7 @@ class MucTab(ChatTab): callback=callback, reason=reason) - def change_role(self, nick, role, reason=''): + def change_role(self, nick: str, role: str, reason=''): """ Change the role of a nick """ @@ -238,7 +242,7 @@ class MucTab(ChatTab): self.core.xmpp, self.name, nick, reason, role, callback=callback) @refresh_wrapper.conditional - def print_info(self, nick): + def print_info(self, nick: str) -> bool: """Print information about a user""" user = self.get_user_by_name(nick) if not user: @@ -269,7 +273,7 @@ class MucTab(ChatTab): self.add_message(info, typ=0) return True - def change_topic(self, topic): + def change_topic(self, topic: str): """Change the current topic""" muc.change_subject(self.core.xmpp, self.name, topic) @@ -331,7 +335,7 @@ class MucTab(ChatTab): self.text_win.rebuild_everything(self._text_buffer) @refresh_wrapper.conditional - def set_nick_color(self, nick, color): + def set_nick_color(self, nick: str, color: str) -> bool: "Set a custom color for a nick, permanently" user = self.get_user_by_name(nick) if color not in xhtml.colors and color not in ('unset', 'random'): @@ -374,7 +378,7 @@ class MucTab(ChatTab): self.send_composing_chat_state(empty_after) return False - def get_nick(self): + def get_nick(self) -> str: if config.get('show_muc_jid'): return self.name bookmark = self.core.bookmarks[self.name] @@ -479,7 +483,7 @@ class MucTab(ChatTab): status_codes.add(status_code.attrib['code']) self.own_join(from_nick, new_user, status_codes) - def own_join(self, from_nick, new_user, status_codes): + def own_join(self, from_nick: str, new_user: User, status_codes: Set[str]): """ Handle the last presence we received, entering the room """ @@ -500,7 +504,7 @@ class MucTab(ChatTab): self.general_jid): color = dump_tuple(new_user.color) else: - color = 3 + color = "3" info_col = dump_tuple(get_theme().COLOR_INFORMATION_TEXT) warn_col = dump_tuple(get_theme().COLOR_WARNING_TEXT) @@ -848,11 +852,11 @@ class MucTab(ChatTab): self.add_message(kick_msg, typ=2) def on_user_leave_groupchat(self, - user, - jid, - status, - from_nick, - from_room, + user: User, + jid: JID, + status: str, + from_nick: str, + from_room: JID, server_initiated=False): """ When an user leaves a groupchat @@ -960,17 +964,12 @@ class MucTab(ChatTab): self.general_jid) if hide_status_change < -1: hide_status_change = -1 - if ((hide_status_change == -1 or \ - user.has_talked_since(hide_status_change) or\ - user.nick == self.own_nick)\ - and\ - (affiliation != user.affiliation or\ - role != user.role or\ - show != user.show or\ - status != user.status))\ - or\ - (affiliation != user.affiliation or\ - role != user.role): + if ((hide_status_change == -1 + or user.has_talked_since(hide_status_change) + or user.nick == self.own_nick) and + (affiliation != user.affiliation or role != user.role + or show != user.show or status != user.status)) or ( + affiliation != user.affiliation or role != user.role): # display the message in the room self._text_buffer.add_message(msg) self.core.on_user_changed_status_in_private( diff --git a/poezio/tabs/rostertab.py b/poezio/tabs/rostertab.py index 11473e83..9f609f61 100644 --- a/poezio/tabs/rostertab.py +++ b/poezio/tabs/rostertab.py @@ -1114,10 +1114,8 @@ class RosterInfoTab(Tab): if key == '^M': selected_row = self.roster_win.get_selected_row() res = self.input.do_command(key, raw=raw) - if res and not isinstance(self.input, windows.Input): - return True - elif res: - return False + if res: + return not isinstance(self.input, windows.Input) if key == '^M': self.core.on_roster_enter_key(selected_row) return selected_row diff --git a/poezio/theming.py b/poezio/theming.py index 6491e03c..db1ccb39 100755 --- a/poezio/theming.py +++ b/poezio/theming.py @@ -281,7 +281,7 @@ class Theme: (224, -1), (225, -1), (226, -1), (227, -1)] # XEP-0392 consistent color generation palette placeholder # it’s generated on first use when accessing the ccg_palette property - CCG_PALETTE = None + CCG_PALETTE = None # type: Optional[Dict[float, int]] CCG_Y = 0.5**0.45 # yapf: enable @@ -566,8 +566,8 @@ def reload_theme() -> Optional[str]: if hasattr(new_theme, 'theme'): theme = new_theme.theme prepare_ccolor_palette(theme) - else: - return 'No theme present in the theme file' + return None + return 'No theme present in the theme file' if __name__ == '__main__': diff --git a/poezio/windows/base_wins.py b/poezio/windows/base_wins.py index eaedd82b..89c4b73c 100644 --- a/poezio/windows/base_wins.py +++ b/poezio/windows/base_wins.py @@ -15,6 +15,8 @@ log = logging.getLogger(__name__) import curses import string +from typing import Optional, Tuple + from poezio.theming import to_curses_attr, read_tuple FORMAT_CHAR = '\x19' @@ -51,7 +53,7 @@ class Win: if self._win is None: self._win = DummyWin() - def resize(self, height, width, y, x): + def resize(self, height: int, width: int, y: int, x: int): """ Override if something has to be done on resize """ @@ -81,13 +83,13 @@ class Win: except: pass - def move(self, y, x): + def move(self, y: int, x: int): try: self._win.move(y, x) except: pass - def addstr_colored(self, text, y=None, x=None): + def addstr_colored(self, text: str, y=None, x=None): """ Write a string on the window, setting the attributes as they are in the string. @@ -146,7 +148,7 @@ class Win: next_attr_char = text.find(FORMAT_CHAR) self.addstr(text) - def finish_line(self, color=None): + def finish_line(self, color: Optional[Tuple] = None): """ Write colored spaces until the end of line """ diff --git a/poezio/windows/funcs.py b/poezio/windows/funcs.py index 3648bac3..d118f353 100644 --- a/poezio/windows/funcs.py +++ b/poezio/windows/funcs.py @@ -3,16 +3,17 @@ Standalone functions used by the modules """ import string -DIGITS = string.digits + '-' - +from typing import Optional, List from poezio.windows.base_wins import FORMAT_CHAR, format_chars +DIGITS = string.digits + '-' + -def find_first_format_char(text, chars=None): - if chars is None: - chars = format_chars +def find_first_format_char(text: str, + chars: Optional[List[str]] = None) -> int: + to_find = chars or format_chars pos = -1 - for char in chars: + for char in to_find: p = text.find(char) if p == -1: continue @@ -21,7 +22,7 @@ def find_first_format_char(text, chars=None): return pos -def truncate_nick(nick, size=10): +def truncate_nick(nick: str, size=10) -> str: if size < 1: size = 1 if nick and len(nick) > size: @@ -29,7 +30,7 @@ def truncate_nick(nick, size=10): return nick -def parse_attrs(text, previous=None): +def parse_attrs(text: str, previous: Optional[List[str]] = None) -> List[str]: next_attr_char = text.find(FORMAT_CHAR) if previous: attrs = previous diff --git a/poezio/windows/info_bar.py b/poezio/windows/info_bar.py index 6e338a78..f4ba1f1f 100644 --- a/poezio/windows/info_bar.py +++ b/poezio/windows/info_bar.py @@ -32,7 +32,8 @@ class GlobalInfoBar(Win): show_inactive = config.get('show_inactive_tabs') for nb, tab in enumerate(self.core.tabs): - if not tab: continue + if not tab: + continue color = tab.color if not show_inactive and color is get_theme().COLOR_TAB_NORMAL: continue @@ -72,8 +73,10 @@ class VerticalGlobalInfoBar(Win): self._win.erase() sorted_tabs = [tab for tab in self.core.tabs if tab] if not config.get('show_inactive_tabs'): - sorted_tabs = [tab for tab in sorted_tabs if\ - tab.vertical_color != get_theme().COLOR_VERTICAL_TAB_NORMAL] + sorted_tabs = [ + tab for tab in sorted_tabs + if tab.vertical_color != get_theme().COLOR_VERTICAL_TAB_NORMAL + ] nb_tabs = len(sorted_tabs) use_nicks = config.get('use_tab_nicks') if nb_tabs >= height: |