Coding style.

- More import tidying.
- Fix line lengths.
- Dead code in tests.
- lambdas.
- Tests pass regardless of term type.
This commit is contained in:
Andrew Hamilton 2021-11-22 19:53:37 +10:00
parent 2d9a475833
commit d1e538f5f3
11 changed files with 177 additions and 43 deletions

View file

@ -32,17 +32,17 @@ import sys
import time import time
import docopt import docopt
import fill3
import fill3.terminal as terminal
import pygments.styles import pygments.styles
import pyinotify import pyinotify
import termstr
import eris import eris
import eris.tools as tools import eris.tools as tools
import eris.worker as worker import eris.worker as worker
import eris.paged_list as paged_list import eris.paged_list as paged_list
import fill3
import fill3.terminal as terminal
import sorted_collection import sorted_collection
import termstr
USAGE = """ USAGE = """
@ -316,8 +316,8 @@ class Summary:
Entry.MAX_WIDTH = max((len(entry) for entry in self._entries), Entry.MAX_WIDTH = max((len(entry) for entry in self._entries),
default=0) default=0)
if (len(path) - 2) == self._max_path_length: if (len(path) - 2) == self._max_path_length:
self._max_path_length = max(((len(entry.path) - 2) self._max_path_length = max(
for entry in self._entries), default=0) ((len(entry.path) - 2) for entry in self._entries), default=0)
x, y = self._cursor_position x, y = self._cursor_position
if y == len(self._entries): if y == len(self._entries):
self._cursor_position = x, y - 1 self._cursor_position = x, y - 1
@ -370,7 +370,8 @@ class Summary:
log.log_message("Started sync with filesystem…") log.log_message("Started sync with filesystem…")
start_time = time.time() start_time = time.time()
all_paths = set() all_paths = set()
for path in fix_paths(self._root_path, codebase_files(self._root_path)): for path in fix_paths(self._root_path,
codebase_files(self._root_path)):
await asyncio.sleep(0) await asyncio.sleep(0)
all_paths.add(path) all_paths.add(path)
if path in cache: if path in cache:
@ -387,7 +388,8 @@ class Summary:
await asyncio.sleep(0) await asyncio.sleep(0)
self.on_file_deleted(path) self.on_file_deleted(path)
duration = time.time() - start_time duration = time.time() - start_time
log.log_message(f"Finished sync with filesystem. {round(duration, 2)} secs") log.log_message(f"Finished sync with filesystem. "
f"{round(duration, 2)} secs")
def _sweep_up(self, x, y): def _sweep_up(self, x, y):
yield from reversed(self._entries[y][:x]) yield from reversed(self._entries[y][:x])
@ -641,11 +643,12 @@ class Help:
self.view = fill3.View.from_widget(fill3.Text(help_text)) self.view = fill3.View.from_widget(fill3.Text(help_text))
self.widget = fill3.Border(self.view, title="Help") self.widget = fill3.Border(self.view, title="Help")
portal = self.view.portal portal = self.view.portal
self.key_map = {"h": self._exit_help, terminal.UP_KEY: portal.scroll_up, self.key_map = {
"h": self._exit_help, terminal.UP_KEY: portal.scroll_up,
terminal.DOWN_KEY: portal.scroll_down, terminal.DOWN_KEY: portal.scroll_down,
terminal.LEFT_KEY: portal.scroll_left, terminal.LEFT_KEY: portal.scroll_left,
terminal.RIGHT_KEY: portal.scroll_right, terminal.RIGHT_KEY: portal.scroll_right, "q": self._exit_help,
"q": self._exit_help, terminal.ESC: self._exit_help} terminal.ESC: self._exit_help}
def _exit_help(self): def _exit_help(self):
self.screen._is_help_visible = False self.screen._is_help_visible = False
@ -1122,7 +1125,9 @@ def main(root_path, loop, worker_count=None, editor_command=None, theme=None,
screen.editor_command = editor_command screen.editor_command = editor_command
log.log_message("Program started.") log.log_message("Program started.")
jobs_added_event.set() jobs_added_event.set()
callback = lambda event: on_filesystem_event(event, summary, root_path,
def callback(event):
on_filesystem_event(event, summary, root_path,
appearance_changed_event) appearance_changed_event)
notifier = setup_inotify(root_path, loop, callback, is_path_excluded) notifier = setup_inotify(root_path, loop, callback, is_path_excluded)
try: try:
@ -1136,8 +1141,8 @@ def main(root_path, loop, worker_count=None, editor_command=None, theme=None,
loop.stop() loop.stop()
loop.create_task(summary.sync_with_filesystem( loop.create_task(summary.sync_with_filesystem(
appearance_changed_event, log)) appearance_changed_event, log))
for worker in screen.workers: for worker_ in screen.workers:
loop.create_task(worker.future) loop.create_task(worker_.future)
if sys.stdout.isatty(): if sys.stdout.isatty():
with fill3.context(loop, appearance_changed_event, screen, with fill3.context(loop, appearance_changed_event, screen,
exit_loop=exit_loop): exit_loop=exit_loop):

View file

@ -69,7 +69,8 @@ STATUS_MEANINGS = [
STATUS_TO_TERMSTR = { STATUS_TO_TERMSTR = {
status: termstr.TermStr(" ", termstr.CharStyle(bg_color=color)) status: termstr.TermStr(" ", termstr.CharStyle(bg_color=color))
for status, color in _STATUS_COLORS.items()} for status, color in _STATUS_COLORS.items()}
STATUS_TO_TERMSTR[Status.pending] = termstr.TermStr(".").fg_color(termstr.Color.grey_100) STATUS_TO_TERMSTR[Status.pending] = termstr.TermStr(".").fg_color(
termstr.Color.grey_100)
def get_ls_color_codes(): def get_ls_color_codes():
@ -334,9 +335,12 @@ def python_coverage(path):
def _function_body_lines(python_source): def _function_body_lines(python_source):
ranges = [] ranges = []
class FuncNodeVisitor(ast.NodeVisitor): class FuncNodeVisitor(ast.NodeVisitor):
def _line_range(self, body): def _line_range(self, body):
return body[0].lineno - 1, body[-1].end_lineno return body[0].lineno - 1, body[-1].end_lineno
def visit_FunctionDef(self, node): def visit_FunctionDef(self, node):
ranges.append(self._line_range(node.body)) ranges.append(self._line_range(node.body))
visit_AsyncFunctionDef = visit_FunctionDef visit_AsyncFunctionDef = visit_FunctionDef
@ -467,7 +471,8 @@ def godoc(path):
with tempfile.TemporaryDirectory() as temp_dir: with tempfile.TemporaryDirectory() as temp_dir:
symlink_path = os.path.join(temp_dir, "file.go") symlink_path = os.path.join(temp_dir, "file.go")
os.symlink(os.path.abspath(path), symlink_path) os.symlink(os.path.abspath(path), symlink_path)
stdout, stderr, returncode = _do_command(["go", "doc", "."], cwd=temp_dir) stdout, stderr, returncode = _do_command(["go", "doc", "."],
cwd=temp_dir)
os.remove(symlink_path) os.remove(symlink_path)
status = (Status.not_applicable if stdout.strip() == "" or returncode != 0 status = (Status.not_applicable if stdout.strip() == "" or returncode != 0
else Status.ok) else Status.ok)
@ -493,6 +498,7 @@ def make_tool_function(dependencies, command, url=None, error_status=None,
command_parts = command.split() command_parts = command.split()
executables = set([command_parts[0]]) executables = set([command_parts[0]])
error_status = None if error_status is None else Status[error_status] error_status = None if error_status is None else Status[error_status]
@deps(deps=set(dependencies), url=url, executables=executables) @deps(deps=set(dependencies), url=url, executables=executables)
def func(path): def func(path):
return _run_command(command_parts + [path], error_status, has_color, return _run_command(command_parts + [path], error_status, has_color,
@ -710,8 +716,8 @@ def splitext(path):
@functools.lru_cache() @functools.lru_cache()
def is_tool_available(tool): def is_tool_available(tool):
if (hasattr(tool, "command") and if (hasattr(tool, "command") and tool.command.startswith(
tool.command.startswith(f"{PYTHON_EXECUTABLE} -m ")): f"{PYTHON_EXECUTABLE} -m ")):
return importlib.util.find_spec(tool.command.split()[2]) is not None return importlib.util.find_spec(tool.command.split()[2]) is not None
try: try:
return all(shutil.which(executable) for executable in tool.executables) return all(shutil.which(executable) for executable in tool.executables)
@ -720,7 +726,8 @@ def is_tool_available(tool):
def tools_for_path(path): def tools_for_path(path):
git_tools = [git_diff, git_blame, git_log] if os.path.exists(".git") else [] git_tools = ([git_diff, git_blame, git_log]
if os.path.exists(".git") else [])
root, ext = splitext(path) root, ext = splitext(path)
extra_tools = [] if ext == "" else _tools_for_extension().get(ext[1:], []) extra_tools = [] if ext == "" else _tools_for_extension().get(ext[1:], [])
tools = generic_tools() + git_tools + extra_tools tools = generic_tools() + git_tools + extra_tools

View file

@ -99,7 +99,8 @@ def make_summary_page(project_name, summary):
return make_page(body_html, "Summary of " + project_name) return make_page(body_html, "Summary of " + project_name)
def run(server_class=http.server.HTTPServer, handler_class=Webserver, port=8080): def run(server_class=http.server.HTTPServer, handler_class=Webserver,
port=8080):
server_address = ("", port) server_address = ("", port)
httpd = server_class(server_address, handler_class) httpd = server_class(server_address, handler_class)
print("Starting httpd…") print("Starting httpd…")

View file

@ -37,8 +37,8 @@ class Worker:
async def run_tool(self, path, tool): async def run_tool(self, path, tool):
while True: while True:
self.process.stdin.write( self.process.stdin.write(f"{tool.__qualname__}\n{path}\n"
f"{tool.__qualname__}\n{path}\n".encode("utf-8", "surrogatepass")) .encode("utf-8", "surrogatepass"))
data = await self.process.stdout.readline() data = await self.process.stdout.readline()
if data == b"": if data == b"":
await self.create_process() await self.create_process()

View file

@ -9,14 +9,13 @@ import shutil
import tempfile import tempfile
import unittest import unittest
os.environ["TERM"] = "xterm-256color"
import fill3 import fill3
import golden import golden
import eris.__main__ as __main__ import eris.__main__ as __main__
os.environ["TERM"] = "xterm-256color"
_DIMENSIONS = (100, 60) _DIMENSIONS = (100, 60)
@ -68,18 +67,15 @@ class ScreenWidgetTestCase(unittest.TestCase):
_assert_widget_appearance(self.main_widget, "golden-files/help") _assert_widget_appearance(self.main_widget, "golden-files/help")
def test_log_appearance(self): def test_log_appearance(self):
log_shown = _widget_to_string(self.main_widget) _assert_widget_appearance(self.main_widget,
"golden-files/log-original")
self.main_widget.toggle_log() self.main_widget.toggle_log()
log_hidden = _widget_to_string(self.main_widget)
actual = "shown:\n%s\nhidden:\n%s" % (log_shown, log_hidden)
_assert_widget_appearance(self.main_widget, "golden-files/log") _assert_widget_appearance(self.main_widget, "golden-files/log")
def test_window_orientation(self): def test_window_orientation(self):
window_left_right = _widget_to_string(self.main_widget) _assert_widget_appearance(self.main_widget,
"golden-files/window-orientation-original")
self.main_widget.toggle_window_orientation() self.main_widget.toggle_window_orientation()
window_top_bottom = _widget_to_string(self.main_widget)
actual = ("left-right:\n%s\ntop-bottom:\n%s" %
(window_left_right, window_top_bottom))
_assert_widget_appearance(self.main_widget, _assert_widget_appearance(self.main_widget,
"golden-files/window-orientation") "golden-files/window-orientation")
@ -130,8 +126,10 @@ class SummarySyncWithFilesystemTestCase(unittest.TestCase):
self.appearance_changed_event = asyncio.Event() self.appearance_changed_event = asyncio.Event()
self.summary = __main__.Summary(self.temp_dir, self.jobs_added_event) self.summary = __main__.Summary(self.temp_dir, self.jobs_added_event)
self.loop = asyncio.new_event_loop() self.loop = asyncio.new_event_loop()
callback = lambda event: __main__.on_filesystem_event(
event, self.summary, self.temp_dir, self.appearance_changed_event) def callback(event):
__main__.on_filesystem_event(event, self.summary, self.temp_dir,
self.appearance_changed_event)
__main__.setup_inotify(self.temp_dir, self.loop, callback, __main__.setup_inotify(self.temp_dir, self.loop, callback,
__main__.is_path_excluded) __main__.is_path_excluded)
_touch(self.foo_path) _touch(self.foo_path)

View file

@ -0,0 +1,60 @@
┏━━━━━━━━ Summary of project ━━━━━━━━┓┌────────────────────────────────────────────────────────────┐
┃ ┃│Nothing selected │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛│ │
┌─────────────── Log ────────────────┐│ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
└────────────────────────────────────┘└────────────────────────────────────────────────────────────┘
 help quit tab:focus turn log edit next sort refresh fullscreen open 

View file

@ -0,0 +1,60 @@
┏━━━━━━━━ Summary of project ━━━━━━━━┓┌────────────────────────────────────────────────────────────┐
┃ ┃│Nothing selected │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┃ ┃│ │
┗━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┛│ │
┌─────────────── Log ────────────────┐│ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
│ ││ │
└────────────────────────────────────┘└────────────────────────────────────────────────────────────┘
 help quit tab:focus turn log edit next sort refresh fullscreen open 

View file

@ -11,7 +11,7 @@ import eris.paged_list as paged_list
class PagedListTestCase(unittest.TestCase): class PagedListTestCase(unittest.TestCase):
def test_batch(self): def test_batch(self):
self.assertEqual(list(paged_list.batch(iter([3,4,5,6,7]), 2)), self.assertEqual(list(paged_list.batch(iter([3, 4, 5, 6, 7]), 2)),
[[3, 4], [5, 6], [7]]) [[3, 4], [5, 6], [7]])
def test_getitem(self): def test_getitem(self):

View file

@ -7,14 +7,13 @@ import shutil
import unittest import unittest
import unittest.mock import unittest.mock
os.environ["TERM"] = "xterm-256color"
import fill3 import fill3
import golden import golden
import eris.tools as tools import eris.tools as tools
os.environ["TERM"] = "xterm-256color"
os.environ["TZ"] = "GMT" os.environ["TZ"] = "GMT"
ERIS_ROOT = os.path.dirname(__file__) ERIS_ROOT = os.path.dirname(__file__)

View file

@ -1,6 +1,5 @@
"""Give coloring for file types as in the ls command.""" """Give coloring for file types as in the ls command."""

View file

@ -1,6 +1,7 @@
#!/usr/bin/env python3.9 #!/usr/bin/env python3.9
import os
import pickle import pickle
import unittest import unittest
@ -8,6 +9,7 @@ import unittest
import termstr import termstr
os.environ["TERM"] = "xterm-256color"
ESC = "\x1b" ESC = "\x1b"
@ -105,14 +107,16 @@ class TermStrTests(unittest.TestCase):
self.assertEqual(termstr.TermStr("FOO").lower(), foo) self.assertEqual(termstr.TermStr("FOO").lower(), foo)
self.assertEqual(termstr.TermStr("FOO", bold_style).lower(), foo_bold) self.assertEqual(termstr.TermStr("FOO", bold_style).lower(), foo_bold)
self.assertEqual(termstr.TermStr("FOO").swapcase(), foo) self.assertEqual(termstr.TermStr("FOO").swapcase(), foo)
self.assertEqual(termstr.TermStr("FOO", bold_style).swapcase(), foo_bold) self.assertEqual(termstr.TermStr("FOO", bold_style).swapcase(),
foo_bold)
phrase = termstr.TermStr("foo bar") phrase = termstr.TermStr("foo bar")
self.assertEqual(phrase.title(), termstr.TermStr("Foo Bar")) self.assertEqual(phrase.title(), termstr.TermStr("Foo Bar"))
self.assertEqual(phrase.capitalize(), termstr.TermStr("Foo bar")) self.assertEqual(phrase.capitalize(), termstr.TermStr("Foo bar"))
self.assertEqual(foo.upper(), termstr.TermStr("FOO")) self.assertEqual(foo.upper(), termstr.TermStr("FOO"))
self.assertEqual(foo_bold.center(0), foo_bold) self.assertEqual(foo_bold.center(0), foo_bold)
self.assertEqual(foo_bold.center(7), self.assertEqual(foo_bold.center(7),
termstr.TermStr(" ") + foo_bold + termstr.TermStr(" ")) termstr.TermStr(" ") + foo_bold +
termstr.TermStr(" "))
self.assertEqual(foo_bold.ljust(0), foo_bold) self.assertEqual(foo_bold.ljust(0), foo_bold)
self.assertEqual(foo_bold.ljust(5), foo_bold + termstr.TermStr(" ")) self.assertEqual(foo_bold.ljust(5), foo_bold + termstr.TermStr(" "))
self.assertEqual(foo_bold.rjust(0), foo_bold) self.assertEqual(foo_bold.rjust(0), foo_bold)
@ -125,14 +129,15 @@ class TermStrTests(unittest.TestCase):
def test_from_term(self): def test_from_term(self):
def test_round_trip(term_str): def test_round_trip(term_str):
self.assertEqual(termstr.TermStr.from_term(str(term_str)), term_str) self.assertEqual(termstr.TermStr.from_term(str(term_str)),
term_str)
test_round_trip(termstr.TermStr("foo")) test_round_trip(termstr.TermStr("foo"))
test_round_trip(termstr.TermStr("foo").bold()) test_round_trip(termstr.TermStr("foo").bold())
test_round_trip(termstr.TermStr("foo").underline()) test_round_trip(termstr.TermStr("foo").underline())
test_round_trip(termstr.TermStr("foo").italic()) test_round_trip(termstr.TermStr("foo").italic())
test_round_trip(termstr.TermStr("foo").fg_color(termstr.Color.red)) test_round_trip(termstr.TermStr("foo").fg_color(termstr.Color.red))
test_round_trip(termstr.TermStr("foo").fg_color(termstr.Color.red).\ test_round_trip(termstr.TermStr("foo").fg_color(termstr.Color.red).
bg_color(termstr.Color.green)) bg_color(termstr.Color.green))
test_round_trip(termstr.TermStr("foo").fg_color(1)) test_round_trip(termstr.TermStr("foo").fg_color(1))
test_round_trip(termstr.TermStr("foo").bg_color(10)) test_round_trip(termstr.TermStr("foo").bg_color(10))