From 8cc4f4e0acefa6729141fc9b9995f7760c206f67 Mon Sep 17 00:00:00 2001 From: Artur Manuel Date: Mon, 5 Aug 2024 02:53:32 +0100 Subject: [PATCH] feat(refactor): refactored code the code from earlier was a class ridden sloppy mess with a bug in one part. i have refactored it to only contain one class full of the data needed, and added some personal changes which i think are nice! --- flake.nix | 19 ++---- whyfetch/__init__.py | 59 +++++++++-------- whyfetch/data.py | 76 ++++++++++++++++++++++ whyfetch/system_properties.py | 116 ---------------------------------- 4 files changed, 113 insertions(+), 157 deletions(-) create mode 100644 whyfetch/data.py delete mode 100644 whyfetch/system_properties.py diff --git a/flake.nix b/flake.nix index 002ac13..ee1923e 100644 --- a/flake.nix +++ b/flake.nix @@ -29,21 +29,14 @@ # # Use this shell for developing your app. devShells.default = pkgs.mkShell { - inputsFrom = [ self.packages.${system}.whyfetch ]; + inputsFrom = [ + self.packages.${system}.whyfetch + pkgs.pyright + pkgs.black + pkgs.isort + ]; }; - apps = { - whyfetch = { - program = "${self.packages.${system}.whyfetch}/bin/whyfetch"; - type = "app"; - }; - default = { - program = "${self.packages.${system}.default}/bin/whyfetch"; - type = "app"; - }; - }; - - # Shell for poetry. # # nix develop .#poetry diff --git a/whyfetch/__init__.py b/whyfetch/__init__.py index a42ab97..bc9025e 100644 --- a/whyfetch/__init__.py +++ b/whyfetch/__init__.py @@ -1,41 +1,44 @@ -import whyfetch.system_properties as w +from whyfetch.data import Data - -def separator_from_longest_prop(properties: list[w.Prop]): +def separator_from_longest_prop(props: list[str]): j: int = 0 - for i in properties: - if i.length > j: - j = i.length + for i in props: + if len(i) > j: + j = len(i) continue else: continue return "━"*j -colours = { - "red": "\x1b[1;31m", - "blue": "\x1b[1;34m", - "white": "\x1b[1;39m", -} +class Colours: + red: str = "\x1b[1;31m" + blue: str = "\x1b[1;34m" + white: str = "\x1b[1;39m" + magenta: str = "\x1b[1;35m" def __main__(): - kernel: w.Kernel = w.Kernel() - ram: w.Ram = w.Ram() - username: w.Username = w.Username() - os: w.Os = w.Os() - shell: w.Shell = w.Shell() - uptime: w.Uptime = w.Uptime() - locale: w.Locale = w.Locale() + d: Data = Data() + + props: list[str] = [ + f"{d.username}@{d.hostname}", + f"kernel: {d.kernel}", + f"os: {d.os}", + f"shell: {d.shell}", + f"ram: {d.ram}", + f"up: {d.uptime}", + f"locale: {d.locale}" + ] - properties: list[w.Prop] = [ kernel.prop, ram.prop, username.prop, os.prop, uptime.prop, locale.prop ] + separator: str = separator_from_longest_prop(props) - print(f'{colours["white"]}━━━━━━━━━━━━━━━{separator_from_longest_prop(properties)}') - print(f' {colours["red"]}_.----._{colours["white"]} {username.prop.content}@{kernel.node}') - print(f' {colours["red"]}.\' \'.{colours["white"]} {kernel.prop.content}') - print(f'{colours["red"]}/{colours["white"]}._ _.--._ {colours["red"]}\\{colours["white"]} {os.prop.content}') - print(f'|_ \'-\' _.._ `| {shell.prop.content}') - print(f'{colours["blue"]}\\{colours["white"]} `---\' `-{colours["blue"]}/{colours["white"]} {ram.prop.content}') - print(f' {colours["blue"]}\'._ _.\'{colours["white"]} {uptime.prop.content}') - print(f' {colours["blue"]}\'----\'{colours["white"]} {locale.prop.content}') - print(f'━━━━━━━━━━━━━━━{separator_from_longest_prop(properties)}') + print(f'{Colours.white}━━━━━━━━━━━━━━━{separator}') + print(f' {Colours.red}_.----._{Colours.white} {Colours.magenta}{d.username}{Colours.white}@{Colours.magenta}{d.hostname}') + print(f' {Colours.red}.\' \'.{Colours.white} {Colours.magenta}kernel:{Colours.white} {d.kernel}') + print(f'{Colours.red}/{Colours.white}._ _.--._ {Colours.red}\\{Colours.white} {Colours.magenta}os:{Colours.white} {d.os}') + print(f'|_ \'-\' _.._ `| {Colours.magenta}shell:{Colours.white} {d.shell}') + print(f'{Colours.blue}\\{Colours.white} `---\' `-{Colours.blue}/{Colours.white} {Colours.magenta}ram:{Colours.white} {d.ram}') + print(f' {Colours.blue}\'._ _.\'{Colours.white} {Colours.magenta}up:{Colours.white} {d.uptime}') + print(f' {Colours.blue}\'----\'{Colours.white} {Colours.magenta}locale:{Colours.white} {d.locale}') + print(f'━━━━━━━━━━━━━━━{separator}') diff --git a/whyfetch/data.py b/whyfetch/data.py new file mode 100644 index 0000000..cb5de54 --- /dev/null +++ b/whyfetch/data.py @@ -0,0 +1,76 @@ +from typing import Callable, NamedTuple +import getpass as gp +import socket as sk +import platform as pl +import psutil as ps +import shellingham as sh +import locale as lc +import datetime as dt +import time as tm +import os + +ures: pl.uname_result = pl.uname() +sys: str = pl.system() + +class Data: + def __init__(self) -> None: + self.username: str = gp.getuser() + self.hostname: str = sk.gethostname() + self.kernel: str = f"{ures.system} {ures.release} {ures.machine}" + self.os: str = self.get_os() + self.shell: str = self.get_shell() + self.ram: str = self.get_ram() + self.uptime: str = self.get_uptime() + self.locale: str = lc.setlocale(lc.LC_CTYPE) + pass + + def get_os(self) -> str: + if "Linux" == ures.system: + linux_res: dict[str, str] = pl.freedesktop_os_release() + return linux_res['PRETTY_NAME'] + + if [ "FreeBSD", "OpenBSD", "NetBSD" ] not in [ ures.system ]: + return ures.system + + if sys == "Darwin": + mac_res: tuple[str, tuple[str, str, str], str] = pl.mac_ver() + mac_release: str = mac_res[0] + mac_version: str = mac_res[1][0] + return f"{mac_release} {mac_version}" + + if sys == "Windows": + win_res: tuple[str, str, str, str] = pl.win32_ver() + win_edition: str = pl.win32_edition() + win_release: str = win_res[0] + win_ver: str = win_res[1] + return f"{win_release} {win_edition} {win_ver}" + + raise ValueError("Unknown operating system. %r" % sys) + + def get_shell(self) -> str: + try: + shell_info = sh.detect_shell() + shell: str = shell_info[0] + except sh.ShellDetectionFailure: + shell: str = provide_default_shell() + + return shell + + def get_ram(self) -> str: + to_gb: Callable[[int], float] = lambda s: s / (1024 ** 3) + vm: NamedTuple = ps.virtual_memory() + total: float = to_gb(vm.total) + used: float = to_gb(vm.used) + percent: int = int(vm.percent) + return f"{used:.1f}GB / {total:.1f}GB ({percent}%)" + + def get_uptime(self) -> str: + current_uptime: tm.struct_time = tm.gmtime(tm.time() - ps.boot_time()) + return tm.strftime("%H hours, %M minutes, %S seconds", current_uptime) + +def provide_default_shell() -> str: + if os.name == 'nt': + return os.environ['COMSPEC'] + elif os.name == 'posix': + return os.environ['SHELL'] + raise NotImplementedError(f'OS {os.name!r} support not available') diff --git a/whyfetch/system_properties.py b/whyfetch/system_properties.py deleted file mode 100644 index 46124f5..0000000 --- a/whyfetch/system_properties.py +++ /dev/null @@ -1,116 +0,0 @@ -import platform -import psutil -import os -from sys import platform as platform2 -import csv -import pathlib -import shellingham as shelling -import time -import locale - -uname = platform.uname() -svmem = psutil.virtual_memory() -b_to_mb = lambda s : int(s / pow(1024, 2)) - - -class Prop: - def __init__(self, content) -> None: - self.content = content - self.length = len(self.content) - pass - -class Kernel: - def __init__(self) -> None: - self.system: str = uname.system - self.release: str = uname.release - self.machine: str = uname.machine - self.node: str = uname.node - self.prop: Prop = Prop(f"kernel: {self.system} {self.release} {self.machine}") - pass - -class Ram: - def __init__(self) -> None: - self.total: int = svmem.total - self.used: int = svmem.used - self.available = svmem.available - self.prop: Prop = Prop(self.format()) - pass - - def format(self) -> str: - total_in_gb: int = b_to_mb(self.total) - used_in_gb: int = b_to_mb(self.used) - available_in_gb: int = b_to_mb(self.available) - - return f"ram: {used_in_gb}MB/{total_in_gb}MB ({available_in_gb}MB free)" - -class Username: - def __init__(self) -> None: - content: str = self.get_username() - self.prop: Prop = Prop(content) - pass - - def get_username(self) -> str: - username: str = "" - - user_home: str = os.path.expanduser('~') - if platform2 == "win32": - username = user_home.split("\\")[-1] - else: - username = user_home.split("/")[-1] - - return username - -class Os: - def __init__(self) -> None: - content: str = self.get_os_pretty_name() - self.prop: Prop = Prop(content) - pass - def get_os_pretty_name(self) -> str: - path = pathlib.Path("/etc/os-release") - with open(path) as stream: - reader = csv.reader(stream, delimiter="=") - os_release = dict(reader) - - return f"os: {os_release['PRETTY_NAME']}" - -class Shell: - def __init__(self) -> None: - content: str = self.get_shell() - self.prop: Prop = Prop(content) - pass - - def get_shell(self) -> str: - try: - shell = shelling.detect_shell() - except shelling.shellDetectionFailure: - shell = self.provide_default() - - return f"shell: {shell[0]}" - - def provide_default(): - if os.name == 'posix': - return os.environ['SHELL'] - elif os.name == 'nt': - return os.environ['COMSPEC'] - raise NotImplementedError(f'OS {os.name!r} support not available') - -class Uptime: - def __init__(self) -> None: - content: str = f"up: {self.get_uptime()}" - self.prop = Prop(content) - pass - - def get_uptime(self) -> str: - seconds_elapsed = time.time() - psutil.boot_time() - seconds: int = int(seconds_elapsed % 60) - minutes: int = int(seconds_elapsed / 60) % 60 - hours: int = int(seconds_elapsed / pow(60, 2)) - - return f"{hours} hours, {minutes} minutes and {seconds} seconds" - -class Locale: - def __init__(self) -> None: - content: str = f"locale: {locale.setlocale(locale.LC_CTYPE)}" - self.prop: Prop = Prop(content) - pass -