[meld] misc: A tonne of typing work
- From: Kai Willadsen <kaiw src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [meld] misc: A tonne of typing work
- Date: Sun, 6 Jan 2019 02:57:52 +0000 (UTC)
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]