From 79f7bd6a60398db90153b3751e885b5a2bbe4a9d Mon Sep 17 00:00:00 2001 From: Roland Thomas Date: Sun, 23 Nov 2025 19:05:03 -0500 Subject: [PATCH] feat: refine menu lifecycle handling and make bottom bar optional - Allow `bottom_bar` to be `None` in `Falyx` initialization and validation logic. - Updated error messaging to reflect `None` as a valid bottom bar state. - Set `FalyxMode.MENU` explicitly when entering interactive menu mode. - Simplified `menu()` loop by removing unnecessary `asyncio.create_task` wrapping. - Added `always_start_menu` flag to `run()` to allow returning to the menu after CLI execution. - Prevent forced `sys.exit()` when `always_start_menu=True` is provided. - Bumped version to 0.1.86 --- falyx/falyx.py | 18 +++++++++--------- falyx/version.py | 2 +- pyproject.toml | 2 +- 3 files changed, 11 insertions(+), 11 deletions(-) diff --git a/falyx/falyx.py b/falyx/falyx.py index fdec4bc..176b969 100644 --- a/falyx/falyx.py +++ b/falyx/falyx.py @@ -174,7 +174,7 @@ class Falyx: self.hooks: HookManager = HookManager() self.last_run_command: Command | None = None self.key_bindings: KeyBindings = key_bindings or KeyBindings() - self.bottom_bar: BottomBar | str | Callable[[], None] = bottom_bar + self.bottom_bar: BottomBar | str | Callable[[], None] | None = bottom_bar self._never_prompt: bool = never_prompt self._force_confirm: bool = force_confirm self.cli_args: Namespace | None = cli_args @@ -606,7 +606,7 @@ class Falyx: self._bottom_bar = bottom_bar else: raise FalyxError( - "Bottom bar must be a string, callable, or BottomBar instance." + "Bottom bar must be a string, callable, None, or BottomBar instance." ) self._invalidate_prompt_session_cache() @@ -618,8 +618,6 @@ class Falyx: return self.bottom_bar elif isinstance(self.bottom_bar, str): return self.bottom_bar - elif self.bottom_bar is None: - return None return None @cached_property @@ -1197,6 +1195,7 @@ class Falyx: async def menu(self) -> None: """Runs the menu and handles user input.""" logger.info("Starting menu: %s", self.get_title()) + self.options.set("mode", FalyxMode.MENU) self.debug_hooks() if self.welcome_message: self.print_message(self.welcome_message) @@ -1208,8 +1207,7 @@ class Falyx: else: self.console.print(self.table, justify="center") try: - task = asyncio.create_task(self.process_command()) - should_continue = await task + should_continue = await self.process_command() if not should_continue: break except (EOFError, KeyboardInterrupt): @@ -1233,6 +1231,7 @@ class Falyx: root_parser: ArgumentParser | None = None, subparsers: _SubParsersAction | None = None, callback: Callable[..., Any] | None = None, + always_start_menu: bool = False, ) -> None: """ Entrypoint for executing a Falyx CLI application via structured subcommands. @@ -1391,7 +1390,8 @@ class Falyx: if self.cli_args.summary: er.summary() - sys.exit(0) + if not always_start_menu: + sys.exit(0) if self.cli_args.command == "run-all": self.options.set("mode", FalyxMode.RUN_ALL) @@ -1444,7 +1444,7 @@ class Falyx: if self.cli_args.summary: er.summary() - - sys.exit(0) + if not always_start_menu: + sys.exit(0) await self.menu() diff --git a/falyx/version.py b/falyx/version.py index b10da4d..bcb74b8 100644 --- a/falyx/version.py +++ b/falyx/version.py @@ -1 +1 @@ -__version__ = "0.1.85" +__version__ = "0.1.86" diff --git a/pyproject.toml b/pyproject.toml index f6b2d75..a047a71 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -1,6 +1,6 @@ [tool.poetry] name = "falyx" -version = "0.1.85" +version = "0.1.86" description = "Reliable and introspectable async CLI action framework." authors = ["Roland Thomas Jr "] license = "MIT"