at long last, reformat all Python code with 2 space indents

This commit is contained in:
Dmytro Meleshko 2021-04-26 10:11:02 +03:00
parent 74e978d78e
commit dbd76019c8
19 changed files with 367 additions and 366 deletions

View File

@ -4,22 +4,22 @@
base16_name = "eighties" base16_name = "eighties"
name = "base16-" + base16_name name = "base16-" + base16_name
base16_colors = [ base16_colors = [
"#2d2d2d", # 0 "#2d2d2d", # 0
"#393939", # 1 "#393939", # 1
"#515151", # 2 "#515151", # 2
"#747369", # 3 "#747369", # 3
"#a09f93", # 4 "#a09f93", # 4
"#d3d0c8", # 5 "#d3d0c8", # 5
"#e8e6df", # 6 "#e8e6df", # 6
"#f2f0ec", # 7 "#f2f0ec", # 7
"#f2777a", # 8 "#f2777a", # 8
"#f99157", # 9 "#f99157", # 9
"#ffcc66", # a "#ffcc66", # a
"#99cc99", # b "#99cc99", # b
"#66cccc", # c "#66cccc", # c
"#6699cc", # d "#6699cc", # d
"#cc99cc", # e "#cc99cc", # e
"#d27b53", # f "#d27b53", # f
] ]
bg = base16_colors[0x0] bg = base16_colors[0x0]
@ -32,18 +32,18 @@ selection_bg = base16_colors[0x2]
selection_fg = fg selection_fg = fg
ansi_colors = [ ansi_colors = [
base16_colors[int(i, 16)] for i in "0 8 B A D E C 5 3 8 B A D E C 7 9 F 1 2 4 6".split() base16_colors[int(i, 16)] for i in "0 8 B A D E C 5 3 8 B A D E C 7 9 F 1 2 4 6".split()
] ]
link_color = ansi_colors[0xC] link_color = ansi_colors[0xC]
css_variables_prefix = "dotfiles-colorscheme-" css_variables_prefix = "dotfiles-colorscheme-"
css_variables = { css_variables = {
"bg": bg, "bg": bg,
"fg": fg, "fg": fg,
"selection-bg": selection_bg, "selection-bg": selection_bg,
"selection-fg": selection_fg, "selection-fg": selection_fg,
"cursor-bg": cursor_bg, "cursor-bg": cursor_bg,
"cursor-fg": cursor_fg, "cursor-fg": cursor_fg,
**{"base-{:02X}".format(index): color for index, color in enumerate(base16_colors)}, **{"base-{:02X}".format(index): color for index, color in enumerate(base16_colors)},
} }

View File

@ -4,7 +4,7 @@ import _theme as theme
print( print(
"""\ """\
<?xml version="1.0" encoding="UTF-8"?> <?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd"> <!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0"> <plist version="1.0">
@ -14,9 +14,9 @@ print(
def print_color(key_name, color): def print_color(key_name, color):
r, g, b = [float(int(color[2 * i + 1:2 * i + 3], 16)) / 255 for i in range(3)] r, g, b = [float(int(color[2 * i + 1:2 * i + 3], 16)) / 255 for i in range(3)]
print( print(
"""\ """\
<key>{} Color</key> <key>{} Color</key>
<dict> <dict>
<key>Color Space</key> <key>Color Space</key>
@ -29,7 +29,7 @@ def print_color(key_name, color):
<real>{}</real> <real>{}</real>
</dict>\ </dict>\
""".format(key_name, r, g, b) """.format(key_name, r, g, b)
) )
print_color("Background", theme.bg) print_color("Background", theme.bg)
@ -40,7 +40,7 @@ print_color("Cursor Text", theme.cursor_fg)
print_color("Selection Color", theme.selection_bg) print_color("Selection Color", theme.selection_bg)
print_color("Selected Text Color", theme.selection_fg) print_color("Selected Text Color", theme.selection_fg)
for index, color in enumerate(theme.ansi_colors[:16]): for index, color in enumerate(theme.ansi_colors[:16]):
print_color("Ansi " + str(index), color) print_color("Ansi " + str(index), color)
print_color("Link", theme.link_color) print_color("Link", theme.link_color)
print("""\ print("""\

View File

@ -4,7 +4,7 @@ import _theme as theme
def print_color(key_name, color): def print_color(key_name, color):
print("{} {}".format(key_name, color)) print("{} {}".format(key_name, color))
print_color("background", theme.bg) print_color("background", theme.bg)
@ -14,7 +14,7 @@ print_color("cursor_text_color", theme.cursor_fg)
print_color("selection_background", theme.selection_bg) print_color("selection_background", theme.selection_bg)
print_color("selection_foreground", theme.selection_fg) print_color("selection_foreground", theme.selection_fg)
for index, color in enumerate(theme.ansi_colors[:16]): for index, color in enumerate(theme.ansi_colors[:16]):
print_color("color" + str(index), color) print_color("color" + str(index), color)
print_color("url_color", theme.link_color) print_color("url_color", theme.link_color)
print_color("active_border_color", theme.ansi_colors[2]) print_color("active_border_color", theme.ansi_colors[2])

View File

@ -4,9 +4,9 @@ import _theme as theme
import os import os
with open(os.path.join(os.path.dirname(__file__), "prismjs-theme-src.css")) as f: with open(os.path.join(os.path.dirname(__file__), "prismjs-theme-src.css")) as f:
css_src = f.read() css_src = f.read()
for var_name, color in theme.css_variables.items(): for var_name, color in theme.css_variables.items():
css_src = css_src.replace("var(--{}{})".format(theme.css_variables_prefix, var_name), color) css_src = css_src.replace("var(--{}{})".format(theme.css_variables_prefix, var_name), color)
print(css_src) print(css_src)

View File

@ -8,4 +8,4 @@ import _theme as theme
# 0,0,0,0,170,170,170,170,85,85,85,85,255,255,255,255 # 0,0,0,0,170,170,170,170,85,85,85,85,255,255,255,255
for i in range(3): for i in range(3):
print(",".join([str(int(color[2 * i + 1:2 * i + 3], 16)) for color in theme.ansi_colors[:16]])) print(",".join([str(int(color[2 * i + 1:2 * i + 3], 16)) for color in theme.ansi_colors[:16]]))

View File

@ -4,11 +4,11 @@ import _theme as theme
def print_color(key_name, color): def print_color(key_name, color):
print("{}={}".format(key_name, color)) print("{}={}".format(key_name, color))
print_color("background", theme.bg) print_color("background", theme.bg)
print_color("foreground", theme.fg) print_color("foreground", theme.fg)
print_color("cursor", theme.cursor_bg) print_color("cursor", theme.cursor_bg)
for index, color in enumerate(theme.ansi_colors[:16]): for index, color in enumerate(theme.ansi_colors[:16]):
print_color("color" + str(index), color) print_color("color" + str(index), color)

View File

@ -5,5 +5,5 @@ import _theme as theme
print(":root {") print(":root {")
for var_name, color in theme.css_variables.items(): for var_name, color in theme.css_variables.items():
print(" --{}{}: {};".format(theme.css_variables_prefix, var_name, color)) print(" --{}{}: {};".format(theme.css_variables_prefix, var_name, color))
print("}") print("}")

View File

@ -8,15 +8,15 @@ print("let dotfiles_colorscheme_base16_name = '{}'".format(theme.base16_name))
print("let dotfiles_colorscheme_base16_colors = [") print("let dotfiles_colorscheme_base16_colors = [")
gui_to_cterm_mapping = [0, 18, 19, 8, 20, 7, 21, 15, 1, 16, 3, 2, 6, 4, 5, 17] gui_to_cterm_mapping = [0, 18, 19, 8, 20, 7, 21, 15, 1, 16, 3, 2, 6, 4, 5, 17]
for colors_pair in zip(theme.base16_colors[:16], gui_to_cterm_mapping): for colors_pair in zip(theme.base16_colors[:16], gui_to_cterm_mapping):
print("\\ {{'gui': '{}', 'cterm': '{:>02}'}},".format(*colors_pair)) print("\\ {{'gui': '{}', 'cterm': '{:>02}'}},".format(*colors_pair))
print("\\ ]") print("\\ ]")
def print_terminal_color(key_name, color): def print_terminal_color(key_name, color):
print("let terminal_color_{} = '{}'".format(key_name, color)) print("let terminal_color_{} = '{}'".format(key_name, color))
print_terminal_color("background", theme.bg) print_terminal_color("background", theme.bg)
print_terminal_color("foreground", theme.fg) print_terminal_color("foreground", theme.fg)
for index, color in enumerate(theme.ansi_colors[:16]): for index, color in enumerate(theme.ansi_colors[:16]):
print_terminal_color(str(index), color) print_terminal_color(str(index), color)

View File

@ -5,27 +5,27 @@ import json
ANSI_COLOR_NAMES = [ ANSI_COLOR_NAMES = [
"Black", "Black",
"Red", "Red",
"Green", "Green",
"Yellow", "Yellow",
"Blue", "Blue",
"Magenta", "Magenta",
"Cyan", "Cyan",
"White", "White",
] ]
colors = { colors = {
"terminal.background": theme.bg, "terminal.background": theme.bg,
"terminal.foreground": theme.fg, "terminal.foreground": theme.fg,
"terminal.selectionBackground": theme.selection_bg, "terminal.selectionBackground": theme.selection_bg,
"terminalCursor.background": theme.cursor_fg, "terminalCursor.background": theme.cursor_fg,
"terminalCursor.foreground": theme.cursor_bg, "terminalCursor.foreground": theme.cursor_bg,
} }
for color_brightness in [False, True]: for color_brightness in [False, True]:
for color_index, color_name in enumerate(ANSI_COLOR_NAMES): for color_index, color_name in enumerate(ANSI_COLOR_NAMES):
color = theme.ansi_colors[color_index + int(color_brightness) * len(ANSI_COLOR_NAMES)] color = theme.ansi_colors[color_index + int(color_brightness) * len(ANSI_COLOR_NAMES)]
colors["terminal.ansi" + ("Bright" if color_brightness else "") + color_name] = color colors["terminal.ansi" + ("Bright" if color_brightness else "") + color_name] = color
print(json.dumps(colors, ensure_ascii=False, indent=2)) print(json.dumps(colors, ensure_ascii=False, indent=2))

View File

@ -3,17 +3,17 @@
import _theme as theme import _theme as theme
for attr in [ for attr in [
"bg", "bg",
"fg", "fg",
"cursor_bg", "cursor_bg",
"cursor_fg", "cursor_fg",
"selection_bg", "selection_bg",
"selection_fg", "selection_fg",
"link_color", "link_color",
]: ]:
color = getattr(theme, attr) color = getattr(theme, attr)
print("colorscheme_{}={}".format(attr, color[1:])) print("colorscheme_{}={}".format(attr, color[1:]))
print("colorscheme_ansi_colors=(") print("colorscheme_ansi_colors=(")
for color in theme.ansi_colors: for color in theme.ansi_colors:
print(" {}".format(color[1:])) print(" {}".format(color[1:]))
print(")") print(")")

View File

@ -6,6 +6,8 @@ let s:ignored_errors = []
let s:ignored_errors += ['E111'] let s:ignored_errors += ['E111']
" Indent is not a multiple of 4 for comments " Indent is not a multiple of 4 for comments
let s:ignored_errors += ['E114'] let s:ignored_errors += ['E114']
" Indent for continuation lines is smaller than expected
let s:ignored_errors += ['E121']
" Line too long " Line too long
let s:ignored_errors += ['E501'] let s:ignored_errors += ['E501']

View File

@ -1,7 +1,8 @@
[style] [style]
based_on_style = google based_on_style = google
column_limit = 99 column_limit = 99
indent_width = 4 indent_width = 2
continuation_indent_width = 2
blank_lines_between_top_level_imports_and_variables = 2 blank_lines_between_top_level_imports_and_variables = 2
dedent_closing_brackets = true dedent_closing_brackets = true
coalesce_brackets = true coalesce_brackets = true

View File

@ -5,89 +5,89 @@ from pathlib import Path
from typing import Iterable, NoReturn from typing import Iterable, NoReturn
if os.name == "posix": if os.name == "posix":
DOTFILES_CONFIG_DIR: Path = Path.home() / ".config" / "dotfiles" DOTFILES_CONFIG_DIR: Path = Path.home() / ".config" / "dotfiles"
DOTFILES_CACHE_DIR: Path = Path.home() / ".cache" / "dotfiles" DOTFILES_CACHE_DIR: Path = Path.home() / ".cache" / "dotfiles"
def platform_not_supported_error() -> NoReturn: def platform_not_supported_error() -> NoReturn:
raise Exception("platform '{}' is not supported!".format(sys.platform)) raise Exception("platform '{}' is not supported!".format(sys.platform))
def run_chooser(choices: Iterable[str], prompt: str = None, async_read: bool = False) -> int: def run_chooser(choices: Iterable[str], prompt: str = None, async_read: bool = False) -> int:
supports_result_index = True supports_result_index = True
if os.isatty(sys.stderr.fileno()): if os.isatty(sys.stderr.fileno()):
process_args = [ process_args = [
"fzf", "fzf",
"--with-nth=2..", "--with-nth=2..",
"--height=50%", "--height=50%",
"--reverse", "--reverse",
"--tiebreak=index", "--tiebreak=index",
] ]
supports_result_index = False supports_result_index = False
elif sys.platform == "darwin": elif sys.platform == "darwin":
process_args = ["choose", "-i"] process_args = ["choose", "-i"]
elif os.name == "posix": elif os.name == "posix":
process_args = ["rofi", "-dmenu", "-i", "-format", "i"] process_args = ["rofi", "-dmenu", "-i", "-format", "i"]
if prompt is not None: if prompt is not None:
process_args += ["-p", prompt] process_args += ["-p", prompt]
if async_read: if async_read:
process_args += ["-async-pre-read", "0"] process_args += ["-async-pre-read", "0"]
else: else:
platform_not_supported_error() platform_not_supported_error()
chooser_process = subprocess.Popen(process_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE) chooser_process = subprocess.Popen(process_args, stdin=subprocess.PIPE, stdout=subprocess.PIPE)
with chooser_process.stdin as pipe: with chooser_process.stdin as pipe:
for index, choice in enumerate(choices): for index, choice in enumerate(choices):
assert "\n" not in choice assert "\n" not in choice
if not supports_result_index: if not supports_result_index:
pipe.write(str(index).encode()) pipe.write(str(index).encode())
pipe.write(b" ") pipe.write(b" ")
pipe.write(choice.encode()) pipe.write(choice.encode())
pipe.write(b"\n") pipe.write(b"\n")
exit_code: int = chooser_process.wait() exit_code: int = chooser_process.wait()
if exit_code != 0: if exit_code != 0:
raise Exception("chooser process failed with exit code {}".format(exit_code)) raise Exception("chooser process failed with exit code {}".format(exit_code))
chosen_index = int(chooser_process.stdout.read().strip().split()[0]) chosen_index = int(chooser_process.stdout.read().strip().split()[0])
return chosen_index return chosen_index
def send_notification(title: str, message: str, url: str = None) -> None: def send_notification(title: str, message: str, url: str = None) -> None:
if sys.platform == "darwin": if sys.platform == "darwin":
process_args = [ process_args = [
"terminal-notifier", "terminal-notifier",
"-title", "-title",
title, title,
"-message", "-message",
message, message,
"-open", "-open",
] ]
if url is not None: if url is not None:
process_args += [url] process_args += [url]
elif os.name == "posix": elif os.name == "posix":
process_args = [ process_args = [
"notify-send", "notify-send",
"--icon=utilities-terminal", "--icon=utilities-terminal",
"--expire-time=3000", "--expire-time=3000",
title, title,
message, message,
] ]
else: else:
platform_not_supported_error() platform_not_supported_error()
subprocess.run(process_args, check=True) subprocess.run(process_args, check=True)
def set_clipboard(text: str) -> None: def set_clipboard(text: str) -> None:
# TODO: somehow merge program selection with the logic in `zsh/functions.zsh` # TODO: somehow merge program selection with the logic in `zsh/functions.zsh`
if sys.platform == "darwin": if sys.platform == "darwin":
process_args = ["pbcopy"] process_args = ["pbcopy"]
elif os.name == "posix": elif os.name == "posix":
process_args = ["xsel", "--clipboard", "--input"] process_args = ["xsel", "--clipboard", "--input"]
# process_args = ["xclip", "-in", "-selection", "clipboard"] # process_args = ["xclip", "-in", "-selection", "clipboard"]
else: else:
platform_not_supported_error() platform_not_supported_error()
subprocess.run(process_args, input=text.encode(), check=True) subprocess.run(process_args, input=text.encode(), check=True)

View File

@ -9,58 +9,58 @@ from typing import Any, IO
def read_bool(buf: IO[bytes]) -> bool: def read_bool(buf: IO[bytes]) -> bool:
return buf.read(1)[0] == 1 return buf.read(1)[0] == 1
def read_number(buf: IO[bytes]) -> float: def read_number(buf: IO[bytes]) -> float:
return struct.unpack("<d", buf.read(8))[0] return struct.unpack("<d", buf.read(8))[0]
def _read_length(buf: IO[bytes]) -> int: def _read_length(buf: IO[bytes]) -> int:
return struct.unpack("<I", buf.read(4))[0] return struct.unpack("<I", buf.read(4))[0]
def read_string(buf: IO[bytes]) -> str: def read_string(buf: IO[bytes]) -> str:
is_empty = read_bool(buf) is_empty = read_bool(buf)
if is_empty: if is_empty:
return "" return ""
len_ = buf.read(1)[0] len_ = buf.read(1)[0]
if len_ == 0xFF: if len_ == 0xFF:
len_ = _read_length(buf) len_ = _read_length(buf)
return buf.read(len_).decode("utf8") return buf.read(len_).decode("utf8")
def read_dictionary(buf: IO[bytes]) -> dict[str, Any]: def read_dictionary(buf: IO[bytes]) -> dict[str, Any]:
len_ = _read_length(buf) len_ = _read_length(buf)
value: dict[str, Any] = {} value: dict[str, Any] = {}
for _ in range(len_): for _ in range(len_):
key = read_string(buf) key = read_string(buf)
value[key] = read(buf) value[key] = read(buf)
return value return value
def read_list(buf: IO[bytes]) -> list[Any]: def read_list(buf: IO[bytes]) -> list[Any]:
len_ = _read_length(buf) len_ = _read_length(buf)
value: list[Any] = [] value: list[Any] = []
for _ in range(len_): for _ in range(len_):
read_string(buf) read_string(buf)
value.append(read(buf)) value.append(read(buf))
return value return value
def read(buf: IO[bytes]) -> Any: def read(buf: IO[bytes]) -> Any:
type_, _any_type_flag = buf.read(2) type_, _any_type_flag = buf.read(2)
if type_ == 0: if type_ == 0:
return None return None
elif type_ == 1: elif type_ == 1:
return read_bool(buf) return read_bool(buf)
elif type_ == 2: elif type_ == 2:
return read_number(buf) return read_number(buf)
elif type_ == 3: elif type_ == 3:
return read_string(buf) return read_string(buf)
elif type_ == 4: elif type_ == 4:
return read_list(buf) return read_list(buf)
elif type_ == 5: elif type_ == 5:
return read_dictionary(buf) return read_dictionary(buf)
else: else:
raise Exception("unknown property tree type 0x{:02x}".format(type_)) raise Exception("unknown property tree type 0x{:02x}".format(type_))

View File

@ -3,29 +3,29 @@ from fractions import Fraction
def factors(n): def factors(n):
result = set() result = set()
for i in range(1, int(sqrt(n)) + 1): for i in range(1, int(sqrt(n)) + 1):
if n % i == 0: if n % i == 0:
result.add(i) result.add(i)
result.add(n // i) result.add(n // i)
return result return result
def solve_quadratic(a, b, c): def solve_quadratic(a, b, c):
if a == 0: if a == 0:
raise Exception("not a quadratic equation") raise Exception("not a quadratic equation")
else:
d = b ** 2 - 4 * a * c
print("D = " + str(d))
if d < 0:
print("no solutions")
elif d > 0:
sd = sqrt(d)
print("sqrt(D) = " + str(sd))
print("x1 = " + str((-b + sd) / (2 * a)))
print("x2 = " + str((-b - sd) / (2 * a)))
else: else:
d = b ** 2 - 4 * a * c print("x = " + str(-b / (2 * a)))
print("D = " + str(d))
if d < 0:
print("no solutions")
elif d > 0:
sd = sqrt(d)
print("sqrt(D) = " + str(sd))
print("x1 = " + str((-b + sd) / (2 * a)))
print("x2 = " + str((-b - sd) / (2 * a)))
else:
print("x = " + str(-b / (2 * a)))
print("loaded Python calculator") print("loaded Python calculator")

View File

@ -5,18 +5,18 @@ COLORS = [ansi.code_to_chars(30 + color_index) for color_index in range(0, 8)]
def colored(string, *colors): def colored(string, *colors):
return "".join(colors + (string, Style.RESET_ALL)) return "".join(colors + (string, Style.RESET_ALL))
def bright_colored(string, *colors): def bright_colored(string, *colors):
return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL)) return "".join(colors + (Style.BRIGHT, string, Style.RESET_ALL))
def colorize_percent(percent, warning, critical, inverse=False): def colorize_percent(percent, warning, critical, inverse=False):
COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED] COLORS = [Fore.GREEN, Fore.YELLOW, Fore.RED]
color_index = 0 if percent < warning else 1 if percent < critical else 2 color_index = 0 if percent < warning else 1 if percent < critical else 2
if inverse: if inverse:
color_index = 2 - color_index color_index = 2 - color_index
return colored("%.2f%%" % percent, COLORS[color_index]) return colored("%.2f%%" % percent, COLORS[color_index])

View File

@ -1,34 +1,34 @@
def humanize_timedelta(timedelta): def humanize_timedelta(timedelta):
result = [] result = []
days = timedelta.days days = timedelta.days
mm, ss = divmod(timedelta.seconds, 60) mm, ss = divmod(timedelta.seconds, 60)
hh, mm = divmod(mm, 60) hh, mm = divmod(mm, 60)
def plural(n): def plural(n):
return n, "s" if abs(n) != 1 else "" return n, "s" if abs(n) != 1 else ""
if days > 0: if days > 0:
result.append("%d day%s" % plural(days)) result.append("%d day%s" % plural(days))
if hh > 0 or result: if hh > 0 or result:
result.append("%d hour%s" % plural(hh)) result.append("%d hour%s" % plural(hh))
if mm > 0 or result: if mm > 0 or result:
result.append("%d min%s" % plural(mm)) result.append("%d min%s" % plural(mm))
if len(result) <= 1: if len(result) <= 1:
result.append("%d sec%s" % plural(ss)) result.append("%d sec%s" % plural(ss))
return ", ".join(result) return ", ".join(result)
def humanize_bytes(bytes): def humanize_bytes(bytes):
units = ["B", "kB", "MB", "GB"] units = ["B", "kB", "MB", "GB"]
factor = 1 factor = 1
unit = "" unit = ""
for unit in units: for unit in units:
next_factor = factor << 10 next_factor = factor << 10
if bytes < next_factor: if bytes < next_factor:
break break
factor = next_factor factor = next_factor
return "%.2f %s" % (float(bytes) / factor, unit) return "%.2f %s" % (float(bytes) / factor, unit)

View File

@ -13,24 +13,24 @@ logo_line_widths = [len(re.sub(r"{\d}", "", line)) for line in logo_lines]
logo_width = max(logo_line_widths) logo_width = max(logo_line_widths)
for line_index in range(0, max(len(logo_lines), len(info_lines))): for line_index in range(0, max(len(logo_lines), len(info_lines))):
line = "" line = ""
logo_line_width = 0 logo_line_width = 0
if line_index < len(logo_lines): if line_index < len(logo_lines):
logo_line = logo_lines[line_index] logo_line = logo_lines[line_index]
logo_line_width = logo_line_widths[line_index] logo_line_width = logo_line_widths[line_index]
line += Style.BRIGHT line += Style.BRIGHT
line += logo_line.format(*COLORS) line += logo_line.format(*COLORS)
line += Style.RESET_ALL line += Style.RESET_ALL
line += " " * (logo_width - logo_line_width + 3) line += " " * (logo_width - logo_line_width + 3)
if line_index < len(info_lines): if line_index < len(info_lines):
info_line = info_lines[line_index] info_line = info_lines[line_index]
line += info_line line += info_line
print(line) print(line)
print("") print("")

View File

@ -11,202 +11,200 @@ from humanize import humanize_bytes, humanize_timedelta
def get_system_info(): def get_system_info():
info_lines = [] info_lines = []
def info(name, value, *format_args): def info(name, value, *format_args):
line = bright_colored(name + ":", Fore.YELLOW) + " " + value line = bright_colored(name + ":", Fore.YELLOW) + " " + value
if format_args: if format_args:
line = line % format_args line = line % format_args
info_lines.append(line) info_lines.append(line)
username = getuser() username = getuser()
hostname = _get_hostname() hostname = _get_hostname()
info_lines.append( info_lines.append(bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED))
bright_colored(username, Fore.BLUE) + "@" + bright_colored(hostname, Fore.RED) info_lines.append("")
)
info_lines.append("")
distro_id, distro_name, distro_version, distro_codename = _get_distro_info() distro_id, distro_name, distro_version, distro_codename = _get_distro_info()
info("OS", " ".join([distro_name, distro_version, distro_codename])) info("OS", " ".join([distro_name, distro_version, distro_codename]))
logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id) logo_path = os.path.join(os.path.dirname(__file__), "logos", distro_id)
with open(logo_path) as logo_file: with open(logo_path) as logo_file:
logo_lines = logo_file.read().splitlines() logo_lines = logo_file.read().splitlines()
info("Kernel", "%s %s", platform.system(), platform.release()) info("Kernel", "%s %s", platform.system(), platform.release())
info("Uptime", humanize_timedelta(_get_uptime())) info("Uptime", humanize_timedelta(_get_uptime()))
users_info = _get_users() users_info = _get_users()
if users_info: if users_info:
info("Users", users_info) info("Users", users_info)
shell = _get_shell() shell = _get_shell()
if shell is not None: if shell is not None:
info("Shell", shell) info("Shell", shell)
info_lines.append("") info_lines.append("")
cpu_usage_info = _get_cpu_usage() cpu_usage_info = _get_cpu_usage()
if cpu_usage_info is not None: if cpu_usage_info is not None:
info("CPU Usage", "%s", cpu_usage_info) info("CPU Usage", "%s", cpu_usage_info)
info("Memory", "%s / %s (%s)", *_get_memory()) info("Memory", "%s / %s (%s)", *_get_memory())
for disk_info in _get_disks(): for disk_info in _get_disks():
info("Disk (%s)", "%s / %s (%s)", *disk_info) info("Disk (%s)", "%s / %s (%s)", *disk_info)
battery_info = _get_battery() battery_info = _get_battery()
if battery_info is not None: if battery_info is not None:
info("Battery", "%s (%s)", *battery_info) info("Battery", "%s (%s)", *battery_info)
info_lines.append("") info_lines.append("")
for local_ip_address in _get_local_ipv4_addresses(): for local_ip_address in _get_local_ipv4_addresses():
info("Local IPv4 Address (%s)", "%s", *local_ip_address) info("Local IPv4 Address (%s)", "%s", *local_ip_address)
return logo_lines, info_lines return logo_lines, info_lines
def _get_hostname(): def _get_hostname():
hostname = socket.gethostname() hostname = socket.gethostname()
return hostname return hostname
def _get_uptime(): def _get_uptime():
return datetime.now() - datetime.fromtimestamp(psutil.boot_time()) return datetime.now() - datetime.fromtimestamp(psutil.boot_time())
def _get_users(): def _get_users():
users = {} users = {}
for user in psutil.users(): for user in psutil.users():
name = user.name name = user.name
terminal = user.terminal terminal = user.terminal
if name in users: if name in users:
users[name].append(terminal) users[name].append(terminal)
else: else:
users[name] = [terminal] users[name] = [terminal]
result = [] result = []
for name in users: for name in users:
terminals = users[name] terminals = users[name]
colored_name = bright_colored(name, Fore.BLUE) colored_name = bright_colored(name, Fore.BLUE)
colored_terminals = [colored(str(term), Style.DIM, Fore.WHITE) for term in terminals] colored_terminals = [colored(str(term), Style.DIM, Fore.WHITE) for term in terminals]
terminals_str = ", ".join(colored_terminals) terminals_str = ", ".join(colored_terminals)
if len(colored_terminals) > 1: if len(colored_terminals) > 1:
terminals_str = "(%s)" % terminals_str terminals_str = "(%s)" % terminals_str
result.append(colored_name + "@" + terminals_str) result.append(colored_name + "@" + terminals_str)
return ", ".join(result) return ", ".join(result)
def _get_shell(): def _get_shell():
return os.environ.get("SHELL") return os.environ.get("SHELL")
def _get_cpu_usage(): def _get_cpu_usage():
try: try:
percent = psutil.cpu_percent() percent = psutil.cpu_percent()
except Exception as e: except Exception as e:
print("Error in _get_cpu_usage:", e) print("Error in _get_cpu_usage:", e)
return None return None
return colorize_percent(percent, warning=60, critical=80) return colorize_percent(percent, warning=60, critical=80)
def _get_memory(): def _get_memory():
memory = psutil.virtual_memory() memory = psutil.virtual_memory()
return ( return (
humanize_bytes(memory.used), humanize_bytes(memory.used),
humanize_bytes(memory.total), humanize_bytes(memory.total),
colorize_percent(memory.percent, warning=60, critical=80), colorize_percent(memory.percent, warning=60, critical=80),
) )
def _get_disks(): def _get_disks():
result = [] result = []
for disk in psutil.disk_partitions(all=False): for disk in psutil.disk_partitions(all=False):
if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""): if psutil.WINDOWS and ("cdrom" in disk.opts or disk.fstype == ""):
# skip cd-rom drives with no disk in it on Windows; they may raise # skip cd-rom drives with no disk in it on Windows; they may raise
# ENOENT, pop-up a Windows GUI error for a non-ready partition or # ENOENT, pop-up a Windows GUI error for a non-ready partition or
# just hang # just hang
continue continue
usage = psutil.disk_usage(disk.mountpoint) usage = psutil.disk_usage(disk.mountpoint)
result.append(( result.append((
disk.mountpoint, disk.mountpoint,
humanize_bytes(usage.used), humanize_bytes(usage.used),
humanize_bytes(usage.total), humanize_bytes(usage.total),
colorize_percent(usage.percent, warning=70, critical=85), colorize_percent(usage.percent, warning=70, critical=85),
)) ))
return result return result
def _get_battery(): def _get_battery():
if not hasattr(psutil, "sensors_battery"): if not hasattr(psutil, "sensors_battery"):
return None return None
try: try:
battery = psutil.sensors_battery() battery = psutil.sensors_battery()
except Exception as e: except Exception as e:
print("Error in _get_battery:", e) print("Error in _get_battery:", e)
return None return None
if battery is None: if battery is None:
return None return None
percent = battery.percent percent = battery.percent
if battery.power_plugged: if battery.power_plugged:
status = "charging" if percent < 100 else "fully charged" status = "charging" if percent < 100 else "fully charged"
else: else:
status = "%s left" % humanize_timedelta(timedelta(seconds=battery.secsleft)) status = "%s left" % humanize_timedelta(timedelta(seconds=battery.secsleft))
return colorize_percent(percent, critical=10, warning=20, inverse=True), status return colorize_percent(percent, critical=10, warning=20, inverse=True), status
def _get_local_ipv4_addresses(): def _get_local_ipv4_addresses():
result = [] result = []
for interface, addresses in psutil.net_if_addrs().items(): for interface, addresses in psutil.net_if_addrs().items():
for address in addresses: for address in addresses:
if address.family != socket.AF_INET: if address.family != socket.AF_INET:
# allow only IPv4 addresses (skip IPv6 and MAC, for example) # allow only IPv4 addresses (skip IPv6 and MAC, for example)
continue continue
if interface.startswith("lo"): if interface.startswith("lo"):
# skip loopback interfaces # skip loopback interfaces
continue continue
result.append((interface, address.address)) result.append((interface, address.address))
return result return result
def _get_distro_info(): def _get_distro_info():
if psutil.WINDOWS: if psutil.WINDOWS:
return "windows", platform.system(), platform.release(), "" return "windows", platform.system(), platform.release(), ""
elif psutil.OSX: elif psutil.OSX:
import plistlib import plistlib
with open("/System/Library/CoreServices/SystemVersion.plist", "rb") as f: with open("/System/Library/CoreServices/SystemVersion.plist", "rb") as f:
sw_vers = plistlib.load(f) sw_vers = plistlib.load(f)
return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], "" return "mac", sw_vers["ProductName"], sw_vers["ProductVersion"], ""
elif _is_android(): elif _is_android():
from subprocess import check_output from subprocess import check_output
android_version = check_output(["getprop", "ro.build.version.release"]) android_version = check_output(["getprop", "ro.build.version.release"])
return "android", "Android", android_version.decode().strip(), "" return "android", "Android", android_version.decode().strip(), ""
elif psutil.LINUX: elif psutil.LINUX:
import distro import distro
return distro.id(), distro.name(), distro.version(), distro.codename() return distro.id(), distro.name(), distro.version(), distro.codename()
raise NotImplementedError("unsupported OS") raise NotImplementedError("unsupported OS")
def _is_android(): def _is_android():
return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app") return os.path.isdir("/system/app") and os.path.isdir("/system/priv-app")