cli-ih 0.5.1__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,121 @@
1
+ from typing import Callable
2
+ import logging
3
+
4
+ class HandlerClosed(Exception): ...
5
+ class MissingParameter(Exception): ...
6
+
7
+ class CustomFormatter(logging.Formatter):
8
+ """Custom formatter to add colors to log levels."""
9
+
10
+ LEVEL_COLORS = {
11
+ logging.DEBUG: "\033[34m",
12
+ logging.INFO: "\033[0m",
13
+ logging.WARNING: "\033[33m",
14
+ logging.ERROR: "\033[31m",
15
+ logging.CRITICAL: "\033[37;41m"
16
+ }
17
+
18
+ def format(self, record):
19
+ log_color = self.LEVEL_COLORS.get(record.levelno, "\033[0m")
20
+ log_message = super().format(record)
21
+ return f"{log_color}{log_message}\033[0m"
22
+
23
+ def setup_logging():
24
+ log_format = '[%(asctime)s | %(levelname)s]: %(message)s'
25
+ handler = logging.StreamHandler()
26
+ handler.setFormatter(CustomFormatter(log_format))
27
+ logging.basicConfig(level=logging.INFO, handlers=[handler], datefmt='%B %d %H:%M:%S')
28
+
29
+ class InputHandler:
30
+ #logging.basicConfig(level=logging.INFO, format='[%(asctime)s | %(levelname)s]: %(message)s', datefmt='%B %d %H:%M:%S')
31
+ def __init__(self, thread_mode = True):
32
+ self.commands = {}
33
+ self.is_running = False
34
+ self.thread_mode = thread_mode
35
+ self.thread = None
36
+ self.register_default_commands()
37
+
38
+ def register_command(self, name: str, func: Callable, description: str = ""):
39
+ """Registers a command with its associated function."""
40
+ if not description:
41
+ description = "A command"
42
+ if ' ' in name:
43
+ raise SyntaxError("Command name must not have spaces")
44
+ self.commands[name] = {"cmd": func, "description": description}
45
+
46
+ def start(self):
47
+ """Starts the input handler loop in a separate thread if thread mode is enabled."""
48
+ import threading, inspect
49
+ self.is_running = True
50
+
51
+ def run_command(commands: dict, name: str, args: list):
52
+ """Executes a command from the command dictionary if it exists."""
53
+ command = commands.get(name)
54
+ if command:
55
+ func = command.get("cmd")
56
+ if callable(func):
57
+ if str(inspect.signature(func)) == "()":
58
+ raise MissingParameter(f"Command '{name}' must accept an 'args' parameter")
59
+ try:
60
+ func(args)
61
+ except Exception as e:
62
+ raise e
63
+ else:
64
+ raise ValueError(f"The command '{name}' is not callable.")
65
+ else:
66
+ logging.warning(f"Command '{name}' not found.")
67
+
68
+
69
+ def _thread():
70
+ """Continuously listens for user input and processes commands."""
71
+ while self.is_running:
72
+ try:
73
+ user_input = input().strip()
74
+ if not user_input:
75
+ continue
76
+
77
+ cmdargs = user_input.split(' ')
78
+ command_name = cmdargs[0]
79
+ args = cmdargs[1:]
80
+ if command_name in self.commands:
81
+ run_command(self.commands, command_name, args)
82
+ else:
83
+ logging.warning(f"Unknown command: '{command_name}'")
84
+ except EOFError:
85
+ logging.error("Input ended unexpectedly.")
86
+ break
87
+ except KeyboardInterrupt:
88
+ logging.error("Input interrupted.")
89
+ break
90
+ except HandlerClosed:
91
+ logging.info("Input Handler exited.")
92
+ break
93
+ self.is_running = False
94
+ if self.thread_mode:
95
+ self.thread = threading.Thread(target=_thread, daemon=True)
96
+ self.thread.start()
97
+ else:
98
+ _thread()
99
+
100
+ def register_default_commands(self):
101
+ def help(commands):
102
+ str_out = ""
103
+ for command in commands:
104
+ str_out += f"{command}: {commands[command]['description']}\n"
105
+ print(str_out)
106
+
107
+ def debug_mode(args):
108
+ logger = logging.getLogger()
109
+ if logger.getEffectiveLevel() == logging.DEBUG:
110
+ logger.setLevel(logging.INFO)
111
+ logging.info("Debug mode is now off")
112
+ else:
113
+ logger.setLevel(logging.DEBUG)
114
+ logging.debug("Debug mode is now on")
115
+
116
+ def exit_thread(args):
117
+ raise HandlerClosed
118
+ self.register_command("help", lambda args: help(self.commands), "Displays all the available commands")
119
+ self.register_command("debug", debug_mode, "Changes the logging level to DEBUG.")
120
+ self.register_command("exit", exit_thread, "Exits the Input Handler irreversibly.")
121
+ setup_logging()
@@ -0,0 +1,7 @@
1
+ Metadata-Version: 2.1
2
+ Name: cli_ih
3
+ Version: 0.5.1
4
+ Summary: A background command handler for python's command line interface.
5
+ Author-email: Hotment <michatchuplay@gmail.com>
6
+ Requires-Python: >=3.8
7
+ Requires-Dist: logging==0.4.9.6
@@ -0,0 +1,5 @@
1
+ InputHandler/__init__.py,sha256=w4qMQJe00-d-PiXCRQ26fudlbiDzfAl3AsK4UY713R8,4864
2
+ cli_ih-0.5.1.dist-info/METADATA,sha256=iZbebVtc4-up01w3UfkEmzj3MtiFinJPvWv-tWcmBnY,235
3
+ cli_ih-0.5.1.dist-info/WHEEL,sha256=PZUExdf71Ui_so67QXpySuHtCi3-J3wvF4ORK6k_S8U,91
4
+ cli_ih-0.5.1.dist-info/top_level.txt,sha256=1wOYpDwNGBjhQWhD3dRvyWH1Hh4U6HWbAqJAq-p4Izg,13
5
+ cli_ih-0.5.1.dist-info/RECORD,,
@@ -0,0 +1,5 @@
1
+ Wheel-Version: 1.0
2
+ Generator: setuptools (75.6.0)
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
5
+
@@ -0,0 +1 @@
1
+ InputHandler