[meld] misc: A tonne of typing work



commit 89434e1f556acb16f2331385d94102bf821c13b0
Author: Kai Willadsen <kai willadsen gmail com>
Date:   Fri Dec 14 10:49:12 2018 +1000

    misc: A tonne of typing work

 meld/misc.py | 106 +++++++++++++++++++++++++++++++++++++++--------------------
 1 file changed, 71 insertions(+), 35 deletions(-)
---
diff --git a/meld/misc.py b/meld/misc.py
index aa9cf11c..367b7079 100644
--- a/meld/misc.py
+++ b/meld/misc.py
@@ -25,7 +25,19 @@ import os
 import shutil
 import subprocess
 from pathlib import PurePath
-from typing import List
+from typing import (
+    AnyStr,
+    Callable,
+    List,
+    Generator,
+    Union,
+    Mapping,
+    Optional,
+    Pattern,
+    Sequence,
+    Tuple,
+    TYPE_CHECKING,
+)
 
 from gi.repository import Gdk
 from gi.repository import GLib
@@ -34,6 +46,9 @@ from gi.repository import GtkSource
 
 from meld.conf import _
 
+if TYPE_CHECKING:
+    from meld.vcview import ConsoleStream
+
 
 if os.name != "nt":
     from select import select
@@ -55,7 +70,8 @@ def with_focused_pane(function):
     return wrap_function
 
 
-def get_modal_parent(widget: Gtk.Widget = None) -> Gtk.Window:
+def get_modal_parent(widget: Optional[Gtk.Widget] = None) -> Gtk.Window:
+    parent: Gtk.Window
     if not widget:
         from meld.meldapp import app
         parent = app.get_active_window()
@@ -66,7 +82,7 @@ def get_modal_parent(widget: Gtk.Widget = None) -> Gtk.Window:
     return parent
 
 
-def error_dialog(primary, secondary) -> Gtk.ResponseType:
+def error_dialog(primary: str, secondary: str) -> Gtk.ResponseType:
     """A common error dialog handler for Meld
 
     This should only ever be used as a last resort, and for errors that
@@ -81,8 +97,12 @@ def error_dialog(primary, secondary) -> Gtk.ResponseType:
 
 
 def modal_dialog(
-        primary, secondary, buttons, parent=None,
-        messagetype=Gtk.MessageType.WARNING) -> Gtk.ResponseType:
+            primary: str,
+            secondary: str,
+            buttons: Union[Gtk.ButtonsType, Sequence[Tuple[str, int]]],
+            parent: Optional[Gtk.Window] = None,
+            messagetype: Gtk.MessageType = Gtk.MessageType.WARNING
+        ) -> Gtk.ResponseType:
     """A common message dialog handler for Meld
 
     This should only ever be used for interactions that must be resolved
@@ -91,9 +111,8 @@ def modal_dialog(
     Primary must be plain text. Secondary must be valid markup.
     """
 
-    if isinstance(buttons, Gtk.ButtonsType):
-        custom_buttons = []
-    else:
+    custom_buttons: Sequence[Tuple[str, int]] = []
+    if not isinstance(buttons, Gtk.ButtonsType):
         custom_buttons, buttons = buttons, Gtk.ButtonsType.NONE
 
     dialog = Gtk.MessageDialog(
@@ -113,7 +132,8 @@ def modal_dialog(
     return response
 
 
-def user_critical(primary, message):
+def user_critical(
+        primary: str, message: str) -> Callable[[Callable], Callable]:
     """Decorator for when the user must be told about failures
 
     The use case here is for e.g., saving a file, where even if we
@@ -143,11 +163,11 @@ def user_critical(primary, message):
     return wrap
 
 
-def make_tool_button_widget(label):
+def make_tool_button_widget(label_text: str) -> Gtk.HBox:
     """Make a GtkToolButton label-widget suggestive of a menu dropdown"""
     arrow = Gtk.Arrow(
         arrow_type=Gtk.ArrowType.DOWN, shadow_type=Gtk.ShadowType.NONE)
-    label = Gtk.Label(label=label)
+    label = Gtk.Label(label=label_text)
     hbox = Gtk.HBox(spacing=3)
     hbox.pack_end(arrow, True, True, 0)
     hbox.pack_end(label, True, True, 0)
@@ -159,7 +179,10 @@ MELD_STYLE_SCHEME = "meld-base"
 MELD_STYLE_SCHEME_DARK = "meld-dark"
 
 
-def get_base_style_scheme():
+base_style_scheme: Optional[GtkSource.StyleScheme] = None
+
+
+def get_base_style_scheme() -> GtkSource.StyleScheme:
 
     global base_style_scheme
 
@@ -194,10 +217,7 @@ def get_base_style_scheme():
     return base_style_scheme
 
 
-base_style_scheme = None
-
-
-def colour_lookup_with_fallback(name, attribute):
+def colour_lookup_with_fallback(name: str, attribute: str) -> Gdk.RGBA:
     from meld.settings import meldsettings
     source_style = meldsettings.style_scheme
 
@@ -223,7 +243,7 @@ def colour_lookup_with_fallback(name, attribute):
     return colour
 
 
-def get_common_theme():
+def get_common_theme() -> Tuple[Mapping[str, Gdk.RGBA], Mapping[str, Gdk.RGBA]]:
     lookup = colour_lookup_with_fallback
     fill_colours = {
         "insert": lookup("meld:insert", "background"),
@@ -245,7 +265,7 @@ def get_common_theme():
     return fill_colours, line_colours
 
 
-def all_same(iterable):
+def all_same(iterable: Sequence) -> bool:
     """Return True if all elements of the list are equal"""
     sample, has_no_sample = None, True
     for item in iterable or ():
@@ -256,7 +276,7 @@ def all_same(iterable):
     return True
 
 
-def shorten_names(*names) -> List[str]:
+def shorten_names(*names: str) -> List[str]:
     """Remove common parts of a list of paths
 
     For example, `('/tmp/foo1', '/tmp/foo2')` would be summarised as
@@ -278,7 +298,7 @@ def shorten_names(*names) -> List[str]:
     basenames = [p.name for p in paths]
 
     if all_same(basenames):
-        def firstpart(path: PurePath):
+        def firstpart(path: PurePath) -> str:
             if len(path.parts) > 1 and path.parts[0]:
                 return "[%s] " % path.parts[0]
             else:
@@ -288,7 +308,15 @@ def shorten_names(*names) -> List[str]:
     return [name or _("[None]") for name in basenames]
 
 
-def read_pipe_iter(command, workdir, errorstream, yield_interval=0.1):
+SubprocessGenerator = Generator[Union[Tuple[int, str], None], None, None]
+
+
+def read_pipe_iter(
+            command: List[str],
+            workdir: str,
+            errorstream: 'ConsoleStream',
+            yield_interval: float = 0.1,
+        ) -> SubprocessGenerator:
     """Read the output of a shell command iteratively.
 
     Each time 'callback_interval' seconds pass without reading any data,
@@ -297,24 +325,26 @@ def read_pipe_iter(command, workdir, errorstream, yield_interval=0.1):
     """
     class Sentinel:
 
-        def __init__(self):
+        proc: Optional[subprocess.Popen]
+
+        def __init__(self) -> None:
             self.proc = None
 
-        def __del__(self):
+        def __del__(self) -> None:
             if self.proc:
                 errorstream.error("killing '%s'\n" % command[0])
                 self.proc.terminate()
                 errorstream.error("killed (status was '%i')\n" %
                                   self.proc.wait())
 
-        def __call__(self):
+        def __call__(self) -> SubprocessGenerator:
             self.proc = subprocess.Popen(
                 command, cwd=workdir, stdin=subprocess.PIPE,
                 stdout=subprocess.PIPE, stderr=subprocess.PIPE,
                 universal_newlines=True)
             self.proc.stdin.close()
             childout, childerr = self.proc.stdout, self.proc.stderr
-            bits = []
+            bits: List[str] = []
             while len(bits) == 0 or bits[-1] != "":
                 state = select([childout, childerr], [], [childout, childerr],
                                yield_interval)
@@ -347,7 +377,8 @@ def read_pipe_iter(command, workdir, errorstream, yield_interval=0.1):
     return Sentinel()()
 
 
-def write_pipe(command, text, error=None):
+def write_pipe(
+        command: List[str], text: str, error: Optional[int] = None) -> int:
     """Write 'text' into a shell command and discard its stdout output.
     """
     proc = subprocess.Popen(command, stdin=subprocess.PIPE,
@@ -356,7 +387,7 @@ def write_pipe(command, text, error=None):
     return proc.wait()
 
 
-def copy2(src, dst):
+def copy2(src: str, dst: str) -> None:
     """Like shutil.copy2 but ignores chmod errors, and copies symlinks as links
     See [Bug 568000] Copying to NTFS fails
     """
@@ -379,7 +410,7 @@ def copy2(src, dst):
             raise
 
 
-def copytree(src, dst):
+def copytree(src: str, dst: str) -> None:
     """Similar to shutil.copytree, but always copies symlinks and doesn't
     error out if the destination path already exists.
     """
@@ -411,7 +442,8 @@ def copytree(src, dst):
             raise
 
 
-def merge_intervals(interval_list):
+def merge_intervals(
+        interval_list: List[Tuple[int, int]]) -> List[Tuple[int, int]]:
     """Merge a list of intervals
 
     Returns a list of itervals as 2-tuples with all overlapping
@@ -424,12 +456,12 @@ def merge_intervals(interval_list):
     if len(interval_list) < 2:
         return interval_list
 
-    interval_list = collections.deque(sorted(interval_list))
-    merged_intervals = [interval_list.popleft()]
+    interval_deque = collections.deque(sorted(interval_list))
+    merged_intervals = [interval_deque.popleft()]
     current_start, current_end = merged_intervals[-1]
 
-    while interval_list:
-        new_start, new_end = interval_list.popleft()
+    while interval_deque:
+        new_start, new_end = interval_deque.popleft()
 
         if current_end >= new_end:
             continue
@@ -446,7 +478,11 @@ def merge_intervals(interval_list):
     return merged_intervals
 
 
-def apply_text_filters(txt, regexes, apply_fn=None):
+def apply_text_filters(
+            txt: AnyStr,
+            regexes: Sequence[Pattern],
+            apply_fn: Optional[Callable[[int, int], None]] = None
+        ) -> AnyStr:
     """Apply text filters
 
     Text filters "regexes", resolved as regular expressions are applied
@@ -492,7 +528,7 @@ def apply_text_filters(txt, regexes, apply_fn=None):
     return empty_string.join(result_txts)
 
 
-def calc_syncpoint(adj):
+def calc_syncpoint(adj: Gtk.Adjustment) -> float:
     """Calculate a cross-pane adjustment synchronisation point
 
     Our normal syncpoint is the middle of the screen. If the


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]