First Round Async. Much work left to do, dont trust results of hash categorization presently.
This commit is contained in:
+20
-54
@@ -1,33 +1,16 @@
|
||||
# Copyright (C) 2025 James Brotosky, Brandon Wickline
|
||||
#
|
||||
# This program is free software: you can redistribute it and/or modify
|
||||
# it under the terms of the GNU Affero General Public License as published
|
||||
# by the Free Software Foundation, either version 3 of the License, or
|
||||
# (at your option) any later version.
|
||||
#
|
||||
# This program is distributed in the hope that it will be useful,
|
||||
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
# GNU Affero General Public License for more details.
|
||||
#
|
||||
# You should have received a copy of the GNU Affero General Public License
|
||||
# along with this program. If not, see <https://www.gnu.org/licenses/>.
|
||||
|
||||
|
||||
import logging
|
||||
from typing import Any, Callable, List, Optional, Union
|
||||
|
||||
from utils.utils import get_sanitized_input
|
||||
from utils.utils import get_sanitized_input # new async version
|
||||
|
||||
logger = logging.getLogger(__name__)
|
||||
|
||||
|
||||
class Selector:
|
||||
@staticmethod
|
||||
def _display_choices(
|
||||
items: List[Any],
|
||||
label_func: Callable[[Any], str],
|
||||
num_columns: int = 4,
|
||||
num_columns: int = 3,
|
||||
header: str = "Available Choices:"
|
||||
) -> None:
|
||||
sorted_items = sorted(items, key=lambda item: label_func(item).lower())
|
||||
@@ -43,7 +26,7 @@ class Selector:
|
||||
print(line)
|
||||
|
||||
@staticmethod
|
||||
def _select_from_list(
|
||||
async def _select_from_list(
|
||||
items: List[Any],
|
||||
label_func: Callable[[Any], str],
|
||||
allow_multiple: bool = False,
|
||||
@@ -60,7 +43,7 @@ class Selector:
|
||||
|
||||
if allow_multiple:
|
||||
while True:
|
||||
choice = get_sanitized_input("Select an item by number (or Q to finish): ").strip().lower()
|
||||
choice = (await get_sanitized_input("Select an item by number (or Q to finish): ")).strip().lower()
|
||||
if choice == "q":
|
||||
break
|
||||
try:
|
||||
@@ -80,7 +63,7 @@ class Selector:
|
||||
return selected if selected else None
|
||||
else:
|
||||
try:
|
||||
choice = int(get_sanitized_input("Select one item by number: "))
|
||||
choice = int(await get_sanitized_input("Select one item by number: "))
|
||||
if 1 <= choice <= len(sorted_items):
|
||||
selected_item = sorted_items[choice - 1]
|
||||
logger.info(f"Selected: {label_func(selected_item)}")
|
||||
@@ -92,12 +75,8 @@ class Selector:
|
||||
return None
|
||||
|
||||
@staticmethod
|
||||
def select_objects(
|
||||
objects: List[Any],
|
||||
allow_multiple: bool = False,
|
||||
prompt_each: bool = False
|
||||
) -> Union[Optional[Any], List[Any]]:
|
||||
return Selector._select_from_list(
|
||||
async def select_objects(objects: List[Any], allow_multiple: bool = False, prompt_each: bool = False) -> Union[Optional[Any], List[Any]]:
|
||||
return await Selector._select_from_list(
|
||||
objects,
|
||||
label_func=lambda obj: getattr(obj, "name", str(obj)),
|
||||
allow_multiple=allow_multiple,
|
||||
@@ -106,12 +85,8 @@ class Selector:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def select_string(
|
||||
options: List[str],
|
||||
allow_multiple: bool = False,
|
||||
prompt_each: bool = False
|
||||
) -> Union[Optional[str], List[str]]:
|
||||
return Selector._select_from_list(
|
||||
async def select_string(options: List[str], allow_multiple: bool = False, prompt_each: bool = False) -> Union[Optional[str], List[str]]:
|
||||
return await Selector._select_from_list(
|
||||
options,
|
||||
label_func=str,
|
||||
allow_multiple=allow_multiple,
|
||||
@@ -120,12 +95,8 @@ class Selector:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def select_int(
|
||||
options: List[int],
|
||||
allow_multiple: bool = False,
|
||||
prompt_each: bool = False
|
||||
) -> Union[Optional[int], List[int]]:
|
||||
return Selector._select_from_list(
|
||||
async def select_int(options: List[int], allow_multiple: bool = False, prompt_each: bool = False) -> Union[Optional[int], List[int]]:
|
||||
return await Selector._select_from_list(
|
||||
options,
|
||||
label_func=lambda x: str(x),
|
||||
allow_multiple=allow_multiple,
|
||||
@@ -134,16 +105,11 @@ class Selector:
|
||||
)
|
||||
|
||||
@staticmethod
|
||||
def select_value(
|
||||
prompt: str,
|
||||
value_type: type = int,
|
||||
valid_range: Optional[tuple] = None,
|
||||
allow_quit: bool = False
|
||||
) -> Optional[Any]:
|
||||
async def select_value(prompt: str, value_type: type = int, valid_range: Optional[tuple] = None, allow_quit: bool = False) -> Optional[Any]:
|
||||
while True:
|
||||
user_input = get_sanitized_input(prompt).strip().lower()
|
||||
user_input = (await get_sanitized_input(prompt)).strip().lower()
|
||||
if allow_quit and user_input == "q":
|
||||
logger.info("User opted to quit value selection.")
|
||||
logger.debug("User opted to quit value selection.")
|
||||
return None
|
||||
try:
|
||||
value = value_type(user_input)
|
||||
@@ -152,20 +118,20 @@ class Selector:
|
||||
if not (min_val <= value <= max_val):
|
||||
logger.warning(f"Value out of range ({min_val}–{max_val}).")
|
||||
continue
|
||||
logger.info(f"User selected value: {value}")
|
||||
logger.debug(f"User selected value: {value}")
|
||||
return value
|
||||
except ValueError:
|
||||
logger.warning(f"Invalid input. Expected a {value_type.__name__}.")
|
||||
|
||||
@staticmethod
|
||||
def confirm(prompt: str = "Are you sure? (Y/N): ") -> bool:
|
||||
async def confirm(prompt: str = "Are you sure? (Y/N): ") -> bool:
|
||||
while True:
|
||||
response = get_sanitized_input(prompt).strip().lower()
|
||||
response = (await get_sanitized_input(prompt)).strip().lower()
|
||||
if response in ["y", "yes"]:
|
||||
logger.info("User confirmed action.")
|
||||
logger.debug("User confirmed action.")
|
||||
return True
|
||||
elif response in ["n", "no"]:
|
||||
logger.info("User declined action.")
|
||||
logger.debug("User declined action.")
|
||||
return False
|
||||
else:
|
||||
logger.warning("Invalid confirmation input. Expected 'Y' or 'N'.")
|
||||
logger.warning("Invalid confirmation input. Expected 'Y' or 'N'.")
|
||||
|
||||
Reference in New Issue
Block a user