From fb20d1698de48300da63c65c0dbcb25717dcd632 Mon Sep 17 00:00:00 2001 From: Chandra Irugalbandara Date: Mon, 29 Jul 2024 16:41:14 +0000 Subject: [PATCH] feat: added support for Paths, Email and Passwords --- README.md | 31 +++++++++++++++++++++++++++++++ argonauts/decorators.py | 30 ++++++++++++++++++++++++++++++ argonauts/inputs.py | 38 ++++++++++++++++++++++++++++++++++++++ examples/new_stuff.py | 25 +++++++++++++++++++++++++ 4 files changed, 124 insertions(+) create mode 100644 argonauts/inputs.py create mode 100644 examples/new_stuff.py diff --git a/README.md b/README.md index 20b0a9c..dddfd7c 100644 --- a/README.md +++ b/README.md @@ -19,6 +19,8 @@ Argonauts is a Python library that transforms your functions into interactive co - Transform functions into interactive CLIs with a single decorator - Automatic type inference and validation +- Email, Password Support with validation +- Path Support with Autosuggestion - Chainable interactive functions ## 📦 Installation @@ -114,6 +116,35 @@ movie_night() ![Argonauts Demo](public/demo_1.gif) +### Email, Password, and Path Support + +Argonauts provides built-in support for email, password, and path inputs with validation: + +```python +from argonauts import argonaut +from argonauts.inputs import Email, Password, Path + +@argonaut(process_name="Please wait...") +def login(email: Email, password: Password): + """Login with email and password.""" + ... + +@argonaut(process_name="Loading Configurations...") +def configure(config_path: Path): + """Load configurations from a file.""" + ... +``` + +You can customize these Input types by inhereting them and overriding the `validate` method: + +```python +from argonauts.inputs import Path + +class JSONFile(Path): + def validate(self, value: str) -> bool: + return super().validate(value) and value.endswith(".json") +``` + ## 🤝 Contributing We welcome contributions! Please see our [Contributing Guide](CONTRIBUTING.md) for more details. diff --git a/argonauts/decorators.py b/argonauts/decorators.py index 98cb447..1d3986b 100644 --- a/argonauts/decorators.py +++ b/argonauts/decorators.py @@ -6,6 +6,8 @@ from functools import wraps from typing import Any, Callable, get_args, get_origin +from argonauts.inputs import Email, Password, Path + import questionary from rich.console import Console @@ -131,6 +133,34 @@ def create_prompt(name: str, param: inspect.Parameter) -> Any: # noqa validate=lambda text: text.replace(".", "", 1).isdigit() or "Please enter a valid float.", ).ask() + if annotation == list: + return ( + questionary.text( + f"Enter {name} (comma separated):", + default=", ".join(default) if default is not None else "", + validate=lambda text: len(text) > 0 or f"Please enter a valid {name}.", + ) + .ask() + .split(", ") + ) + if annotation == Path: + return questionary.path( + f"Enter {name}:", + default=default if default is not None else "", + validate=lambda path: Path.validate(path) + or f"Please enter a valid {name}.", + ).ask() + if annotation == Password: + return questionary.password( + f"Enter {name}:", + validate=lambda text: len(text) > 0 or f"Please enter a valid {name}.", + ).ask() + if annotation == Email: + return questionary.text( + f"Enter {name}:", + validate=lambda text: Email.validate(text) + or f"Please enter a valid {name}.", + ).ask() raise ValueError(f"Unsupported type: {annotation}") diff --git a/argonauts/inputs.py b/argonauts/inputs.py new file mode 100644 index 0000000..025e164 --- /dev/null +++ b/argonauts/inputs.py @@ -0,0 +1,38 @@ +"""Different Types of Inputs to use with argonauts.""" + +import os +import re + + +class Path: + """Path input with autocompletion.""" + + def __init__(self) -> None: + """Initialize Path input.""" + pass + + @staticmethod + def validate(path: str) -> bool: + """Validate the given path.""" + return os.path.exists(path) + + +class Password: + """Password input with masking.""" + + def __init__(self) -> None: + """Initialize Password input.""" + pass + + +class Email: + """Email input with validation.""" + + def __init__(self) -> None: + """Initialize Email input.""" + pass + + @staticmethod + def validate(email: str) -> bool: + """Validate the given email.""" + return bool(re.match(r"[^@]+@[^@]+\.[^@]+", email)) diff --git a/examples/new_stuff.py b/examples/new_stuff.py new file mode 100644 index 0000000..346b44e --- /dev/null +++ b/examples/new_stuff.py @@ -0,0 +1,25 @@ +"""Example of using the new argonauts API.""" + +import time + +from argonauts import argonaut +from argonauts.inputs import Email, Password, Path + + +@argonaut(process_name="Please wait...") +def login(email: Email, password: Password) -> None: + """Login with email and password.""" + time.sleep(3) + print(f"Logged in with {email}.") + + +@argonaut(process_name="Loading Configurations...") +def configure(config_path: Path) -> None: + """Configure with the given path.""" + time.sleep(3) + print(f"Configured with {config_path}.") + + +if __name__ == "__main__": + login() + configure()