From 5cf8f3921f4d33764770b65ce7ef7fa82a4fd9b9 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?L=C3=A9opold=20Koprivnik?= Date: Mon, 2 Oct 2023 21:24:42 +0200 Subject: [PATCH] No tui option (#6) * adds command line arguments parsing and a no-tui option that will use inquierer instead * bump version --- requirements.txt | 2 ++ src/main.py | 47 ++++++++++++++++++++++++++++++++++++++--------- src/utils.py | 8 ++++++++ src/wizard.py | 36 +++++++++++++++++++++++++++++------- 4 files changed, 77 insertions(+), 16 deletions(-) diff --git a/requirements.txt b/requirements.txt index bb0bd93..827fb1e 100644 --- a/requirements.txt +++ b/requirements.txt @@ -3,3 +3,5 @@ inquirer==3.1.3 toml==0.10.2 importlib==1.0.4 textual==0.38.1 +click-extra==4.6.0 +loguru==0.7.2 \ No newline at end of file diff --git a/src/main.py b/src/main.py index 64ea358..8a52b9a 100644 --- a/src/main.py +++ b/src/main.py @@ -7,11 +7,17 @@ from textual.validation import Length from textual import log from textual.events import Key +from click_extra import extra_command, option, ExtraContext, Parameter -VERSION = "1.0.0" +VERSION = "1.1.0" from wizard import * +BASIC_INFO_QUESTIONS = [ + TextQuestion("name", "Your project's name", [Length(1, failure_description="Your project's name cannot be blank")], "super-octo-project" ), + SelectQuestion("style", "Logo Style", style_names, "first_letter_underlined") +] + class OctoLogoApp(App): BINDINGS = [ ("ctrl+q", "quit", "Quit"), @@ -70,19 +76,42 @@ def compose(self): yield Footer() basic_info_wizard = Wizard(id="basic_info_wizard") - basic_info_wizard.questions = [ - TextQuestion("name", "Your project's name", [Length(1, failure_description="Your project's name cannot be blank")], "super-octo-project" ), - SelectQuestion("style", "Logo Style", style_names, "first_letter_underlined") - ] + basic_info_wizard.questions = BASIC_INFO_QUESTIONS basic_info_wizard.title = "Basic Information" yield basic_info_wizard yield self.loading_wid -def main(): - app = OctoLogoApp() - app.run() - quit(0) +def disable_ansi(ctx: ExtraContext, param: Parameter, val: bool): + ctx.color = not val + + # We must return the value for the main function no_ansi parameter not to be None + return val + +@extra_command(params=[]) +@option("-t", "--no-tui", is_flag=True, help="Dont use the Textual Terminal User Interface") +def main(no_tui: bool): + use_tui = not no_tui + + if use_tui: + # If the tui is enabled, run the textual app + app = OctoLogoApp() + app.run() + quit(0) + else: + # If the tui is disabled, do everything without textual + answers = dict() + + answers.update(inq_ask(BASIC_INFO_QUESTIONS)) + answers.update(inq_ask(styles[answers['style']].module.questions)) + + style = styles[answers['style']].module + result = style.get_image(answers) + save_to = f'output/{answers["name"]}_{int(time())}.png' + + result.save(save_to) + logger.success(f"Image saved to : {save_to}") + if __name__ == "__main__": main() diff --git a/src/utils.py b/src/utils.py index 55eda6c..f63920b 100644 --- a/src/utils.py +++ b/src/utils.py @@ -3,6 +3,14 @@ import os import toml from PIL import Image, ImageDraw +from loguru import logger +from sys import stdout + +logger.remove() +logger.add(stdout, format="[ {time:HH:mm:ss} ]" + " - {level} -> " + "{message}") + def get_text_size(text, font): text_bbox = ImageDraw.Draw(Image.new("RGBA", (1, 1), (0, 0, 0, 0))).textbbox( diff --git a/src/wizard.py b/src/wizard.py index 7c0880d..ec7c1ca 100644 --- a/src/wizard.py +++ b/src/wizard.py @@ -1,3 +1,4 @@ +from utils import logger from textual import log from typing import Any from textual.validation import Validator @@ -6,7 +7,7 @@ from textual.reactive import reactive from textual.message import Message from textual import on - +import inquirer as inq class QuestionBase(): name: str @@ -42,11 +43,6 @@ def as_widget(self): _input.value = self.default_value return _input - -def get_value_by_name_from_option_list(option_list, text) -> Any: - return filter(lambda x: x[0] == text, option_list).__next__()[1] - - class SelectQuestion(QuestionBase): options: list type: str = "select" @@ -201,4 +197,30 @@ def watch_question_index(self): # If the first question has just been selected then disable # the "Back" button since there arent any questions before - self.query_one("#back").disabled = self.question_index == 0 \ No newline at end of file + self.query_one("#back").disabled = self.question_index == 0 + +def validate_text_question(question: SelectQuestion | TextQuestion, value: str) -> bool: + for validator in question.validators: + validation = validator.validate(value) + if not validation.is_valid: + logger.error(validation.failure_descriptions[0]) + return False + + return True + +def inq_ask(questions: list[SelectQuestion | TextQuestion]) -> dict[str, Any]: + answers = dict() + + for question in questions: + if isinstance(question, SelectQuestion): + answers[question.name] = inq.list_input(question.label, choices=question.options, default=question.default_value) + elif isinstance(question, TextQuestion): + while True: + temp = inq.text(question.label, default=question.default_value) + if not validate_text_question(question, temp): + continue + + answers[question.name] = temp + break + + return answers \ No newline at end of file