From b4d3b93da2e23cefb85dd98f1f7f9706aa0402d4 Mon Sep 17 00:00:00 2001
From: mathieui <mathieui@mathieui.net>
Date: Fri, 17 Aug 2018 02:16:03 +0200
Subject: Add typing information and reformat stuff

---
 poezio/bookmarks.py         | 23 ++++++++--------
 poezio/colors.py            | 22 ++++++++-------
 poezio/decorators.py        | 43 +++++++++++++++---------------
 poezio/tabs/confirmtab.py   |  6 ++---
 poezio/tabs/listtab.py      |  6 ++---
 poezio/tabs/muctab.py       | 65 ++++++++++++++++++++++-----------------------
 poezio/tabs/rostertab.py    |  6 ++---
 poezio/theming.py           |  6 ++---
 poezio/windows/base_wins.py | 10 ++++---
 poezio/windows/funcs.py     | 17 ++++++------
 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:
-- 
cgit v1.2.3