Add dependencies

This commit is contained in:
Roland Thomas Jr 2025-05-05 22:41:42 -04:00
parent 2fee87ade9
commit b5da6b9647
Signed by: roland
GPG Key ID: 7C3C2B085A4C2872
8 changed files with 55 additions and 39 deletions

View File

@ -18,6 +18,6 @@ repos:
hooks: hooks:
- id: sync-version - id: sync-version
name: Sync version from pyproject.toml name: Sync version from pyproject.toml
entry: poetry run sync-version entry: python scripts/sync_version.py
language: system language: system
files: ^pyproject\.toml$ files: ^pyproject\.toml$

View File

@ -46,7 +46,6 @@ def get_falyx_parsers() -> FalyxParsers:
falyx_parsers.subparsers.add_parser( falyx_parsers.subparsers.add_parser(
"init-global", help="Set up ~/.config/falyx with example tasks" "init-global", help="Set up ~/.config/falyx with example tasks"
) )
return falyx_parsers return falyx_parsers

View File

@ -27,10 +27,20 @@ TEMPLATE_CONFIG = """\
spinner: true spinner: true
""" """
GLOBAL_TEMPLATE_TASKS = """\
async def cleanup():
print("🧹 Cleaning temp files...")
"""
GLOBAL_CONFIG = """\
async def cleanup():
print("🧹 Cleaning temp files...")
"""
console = Console(color_system="auto") console = Console(color_system="auto")
def init_project(name: str = "."): def init_project(name: str = ".") -> None:
target = Path(name).resolve() target = Path(name).resolve()
target.mkdir(parents=True, exist_ok=True) target.mkdir(parents=True, exist_ok=True)
@ -39,7 +49,7 @@ def init_project(name: str = "."):
if tasks_path.exists() or config_path.exists(): if tasks_path.exists() or config_path.exists():
console.print(f"⚠️ Project already initialized at {target}") console.print(f"⚠️ Project already initialized at {target}")
return return None
tasks_path.write_text(TEMPLATE_TASKS) tasks_path.write_text(TEMPLATE_TASKS)
config_path.write_text(TEMPLATE_CONFIG) config_path.write_text(TEMPLATE_CONFIG)
@ -47,7 +57,7 @@ def init_project(name: str = "."):
print(f"✅ Initialized Falyx project in {target}") print(f"✅ Initialized Falyx project in {target}")
def init_global(): def init_global() -> None:
config_dir = Path.home() / ".config" / "falyx" config_dir = Path.home() / ".config" / "falyx"
config_dir.mkdir(parents=True, exist_ok=True) config_dir.mkdir(parents=True, exist_ok=True)
@ -56,22 +66,9 @@ def init_global():
if tasks_path.exists() or config_path.exists(): if tasks_path.exists() or config_path.exists():
console.print("⚠️ Global Falyx config already exists at ~/.config/falyx") console.print("⚠️ Global Falyx config already exists at ~/.config/falyx")
return return None
tasks_path.write_text( tasks_path.write_text(GLOBAL_TEMPLATE_TASKS)
"""\ config_path.write_text(GLOBAL_CONFIG)
async def cleanup():
print("🧹 Cleaning temp files...")
"""
)
config_path.write_text(
"""\
- key: C
description: Cleanup temp files
action: tasks.cleanup
aliases: [clean, cleanup]
"""
)
console.print("✅ Initialized global Falyx config at ~/.config/falyx") console.print("✅ Initialized global Falyx config at ~/.config/falyx")

View File

@ -19,6 +19,7 @@ from prompt_toolkit.formatted_text import (
from rich.logging import RichHandler from rich.logging import RichHandler
from falyx.themes.colors import OneColors from falyx.themes.colors import OneColors
from falyx.validators import yes_no_validator
logger = logging.getLogger("falyx") logger = logging.getLogger("falyx")
@ -69,18 +70,20 @@ def chunks(iterator, size):
yield chunk yield chunk
async def confirm_async(message: AnyFormattedText = "Are you sure?") -> bool: async def confirm_async(
session: PromptSession = PromptSession() message: AnyFormattedText = "Are you sure?",
while True: prefix: AnyFormattedText = FormattedText([(OneColors.CYAN, "")]),
merged_message: AnyFormattedText = merge_formatted_text( suffix: AnyFormattedText = FormattedText([(OneColors.LIGHT_YELLOW_b, " [Y/n] > ")]),
[message, FormattedText([(OneColors.LIGHT_YELLOW_b, " [Y/n] ")])] session: PromptSession | None = None,
) ) -> bool:
answer: str = (await session.prompt_async(merged_message)).strip().lower() """Prompt the user with a yes/no async confirmation and return True for 'Y'."""
if answer in ("y", "yes"): session = session or PromptSession()
return True merged_message: AnyFormattedText = merge_formatted_text([prefix, message, suffix])
if answer in ("n", "no", ""): answer = await session.prompt_async(
return False merged_message,
print("Please enter y or n.") validator=yes_no_validator(),
)
return True if answer.upper() == "Y" else False
class CaseInsensitiveDict(dict): class CaseInsensitiveDict(dict):

View File

@ -16,7 +16,10 @@ def int_range_validator(minimum: int, maximum: int) -> Validator:
except ValueError: except ValueError:
return False return False
return Validator.from_callable(validate, error_message="Invalid input.") return Validator.from_callable(
validate,
error_message=f"Invalid input. Enter a number between {minimum} and {maximum}.",
)
def key_validator(keys: Sequence[str] | KeysView[str]) -> Validator: def key_validator(keys: Sequence[str] | KeysView[str]) -> Validator:
@ -27,4 +30,17 @@ def key_validator(keys: Sequence[str] | KeysView[str]) -> Validator:
return False return False
return True return True
return Validator.from_callable(validate, error_message="Invalid input.") return Validator.from_callable(
validate, error_message=f"Invalid input. Available keys: {', '.join(keys)}."
)
def yes_no_validator() -> Validator:
"""Validator for yes/no inputs."""
def validate(input: str) -> bool:
if input.upper() not in ["Y", "N"]:
return False
return True
return Validator.from_callable(validate, error_message="Enter 'Y' or 'n'.")

View File

@ -1 +1 @@
__version__ = "0.1.14" __version__ = "0.1.15"

View File

@ -1,6 +1,6 @@
[tool.poetry] [tool.poetry]
name = "falyx" name = "falyx"
version = "0.1.14" version = "0.1.15"
description = "Reliable and introspectable async CLI action framework." description = "Reliable and introspectable async CLI action framework."
authors = ["Roland Thomas Jr <roland@rtj.dev>"] authors = ["Roland Thomas Jr <roland@rtj.dev>"]
license = "MIT" license = "MIT"
@ -13,6 +13,8 @@ prompt_toolkit = "^3.0"
rich = "^13.0" rich = "^13.0"
pydantic = "^2.0" pydantic = "^2.0"
python-json-logger = "^3.3.0" python-json-logger = "^3.3.0"
toml = "^0.10"
pyyaml = "^6.0"
[tool.poetry.group.dev.dependencies] [tool.poetry.group.dev.dependencies]
pytest = "^7.0" pytest = "^7.0"
@ -26,7 +28,6 @@ pytest-cov = "^4.0"
[tool.poetry.scripts] [tool.poetry.scripts]
falyx = "falyx.__main__:main" falyx = "falyx.__main__:main"
sync-version = "scripts.sync_version:main"
[build-system] [build-system]
requires = ["poetry-core>=1.0.0"] requires = ["poetry-core>=1.0.0"]

View File

@ -35,8 +35,8 @@ def test_bootstrap_no_config():
sys_path_before = list(sys.path) sys_path_before = list(sys.path)
bootstrap_path = bootstrap() bootstrap_path = bootstrap()
assert bootstrap_path is None assert bootstrap_path is None
assert str(Path.cwd()) in sys.path
sys.path = sys_path_before sys.path = sys_path_before
assert str(Path.cwd()) not in sys.path
def test_bootstrap_with_global_config(): def test_bootstrap_with_global_config():