Add lib.py, and minor cleanups in menus.py

This commit is contained in:
Ritchie Mwewa
2026-01-03 04:21:36 +02:00
parent b0aef9e204
commit c3335fe990
11 changed files with 58 additions and 46 deletions

View File

@@ -1,6 +1,6 @@
[project]
name = "octosuite"
version = "4.0.0"
version = "4.0.0-beta"
description = "TUI-based toolkit for GitHub-data analysis."
readme = "README.md"
license = "MIT"
@@ -33,4 +33,4 @@ dev = [
]
[project.scripts]
octosuite = "octosuite.main:start"
octosuite = "octosuite.app:start"

View File

@@ -0,0 +1,2 @@
__pkg__ = "octosuite"
__version__ = "4.0.0"

View File

@@ -1,6 +1,6 @@
import sys
from . import console, __pkg__, __version__
from .lib import console, __pkg__, __version__
from .tui.menus import Menus

View File

@@ -5,10 +5,12 @@ import typing as t
import requests
from requests import Response
from .. import __version__
from ..lib import __version__
BASE_URL = "https://api.github.com"
__all__ = ["BASE_URL", "GitHub"]
class GitHub:
def __init__(

View File

@@ -13,20 +13,17 @@ from rich.text import Text
from rich.tree import Tree
from update_checker import UpdateChecker
__pkg__ = "octosuite"
__version__ = "4.0.0"
__author__ = "Ritchie Mwewa"
from . import __pkg__, __version__
__all__ = [
"console",
"__pkg__",
"__author__",
"__version__",
"console",
"preview_response",
"export_response",
"check_updates",
"clear_screen",
"text_banner",
"ascii_banner",
"set_menu_title",
]
@@ -70,7 +67,13 @@ def preview_response(data: t.Union[dict, list], source: str, _type: str):
console.print(data)
def export_response(data, data_type, source, file_formats, output_dir="../exports"):
def export_response(
data: t.Union[dict, list],
data_type: str,
source: str,
file_formats: list,
output_dir: str = "../exports",
):
"""Export data to selected formats using built-in libraries."""
# Create output directory if it doesn't exist
output_dir = Path(output_dir)
@@ -184,15 +187,18 @@ def fill_tree(tree: Tree, data: t.Union[dict, list]) -> Tree:
def check_updates():
checker = UpdateChecker()
result = checker.check(__pkg__, __version__)
if result:
message_dialog(title="Update Available", text=result).run()
else:
message_dialog(
title="Up to Date",
text=f"You're running the current version, {__version__}",
).run()
with console.status("[dim]Checking for updates...[/dim]") as status:
checker = UpdateChecker()
result = checker.check(__pkg__, __version__)
if result:
status.stop()
message_dialog(title="Update Available", text=result).run()
else:
status.stop()
message_dialog(
title="Up to Date",
text=f"You're running the current version, {__version__}",
).run()
def clear_screen():
@@ -200,7 +206,7 @@ def clear_screen():
subprocess.run(["cls" if os.name == "nt" else "clear"])
def text_banner(text: str):
def ascii_banner(text: str):
clear_screen()
ascii_text = pyfiglet.figlet_format(text=text, font="chunky")

View File

@@ -22,10 +22,11 @@ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE."""
__all__ = ["Dialogs"]
class Dialogs:
def __init__(self):
...
def __init__(self): ...
@staticmethod
def quit() -> bool:

View File

@@ -7,9 +7,9 @@ from rich.status import Status
from .dialogs import Dialogs
from .prompts import Prompts
from .. import check_updates, preview_response, export_response, set_menu_title
from .. import console, clear_screen, text_banner
from ..core.models import User, Repo, Org, Search
from ..lib import check_updates, preview_response, export_response, set_menu_title
from ..lib import console, clear_screen, ascii_banner
CUSTOM_STYLE = Style(
[
@@ -22,12 +22,11 @@ INSTRUCTIONS = "↑↓ [move] • ⮠ [select]"
EXPORT_INSTRUCTIONS = "↑↓ [move] • ⮠ [confirm] • spacebar [check]"
POINTER: str = "🖝 "
__all__ = ["Menus"]
dialogs = Dialogs()
prompts = Prompts()
__all__ = ["Menus"]
class Menus:
def __init__(self):
@@ -88,7 +87,7 @@ class Menus:
status.update(f"[dim]Getting {method_name} from {source}...[/dim]")
return method(**params)
def _navigation(self, option, callback, *callback_args):
def _navigation(self, option: str, callback: t.Callable, *callback_args):
"""Handle navigation options (back, quit, change settings)."""
navigation_handlers = {
"back": lambda: self.main(),
@@ -183,7 +182,7 @@ class Menus:
set_menu_title(menu_type="home")
clear_screen()
try:
text_banner(text="octosuite")
ascii_banner(text="octosuite")
action = q.select(
"What action would you like to perform?",
@@ -256,7 +255,7 @@ class Menus:
set_menu_title(menu_type="search")
clear_screen()
if query is None:
text_banner(text="Search")
ascii_banner(text="Search")
query = prompts.prompt(
message="Search Query",
instruction="e.g., machine learning",
@@ -264,7 +263,7 @@ class Menus:
)
clear_screen()
text_banner(text=query)
ascii_banner(text=query)
option = q.select(
"What would you like to do/search?",
@@ -334,7 +333,7 @@ class Menus:
# Execute search if it's a valid method
if option in self.search_methods:
with console.status(
status=f"[dim]Initialising {option} search[/dim]..."
status=f"[dim]Initialising {option} search...[/dim]"
) as status:
# Get pagination params
@@ -350,7 +349,7 @@ class Menus:
)
method = getattr(search, option)
status.update(f"[dim]Searching {option} for {query}[/dim]...")
status.update(f"[dim]Searching {option} for {query}...[/dim]")
data = method()
if data:
@@ -369,7 +368,7 @@ class Menus:
set_menu_title(menu_type="user")
clear_screen()
if username is None:
text_banner(text="User")
ascii_banner(text="User")
username = prompts.prompt(
message="GitHub Username",
instruction="e.g., octocat",
@@ -378,7 +377,7 @@ class Menus:
)
clear_screen()
text_banner(text=username)
ascii_banner(text=username)
option = q.select(
"What would you like to do/get?",
@@ -473,12 +472,12 @@ class Menus:
valid_methods = self.paginated_methods | self.non_paginated_methods
if option in valid_methods:
with Status(
status=f"[dim]Initialising user {option}[/dim]...",
status=f"[dim]Initialising user {option}...[/dim]",
console=console,
) as status:
user = User(name=username)
status.update(f"[dim]Validating user's ({username}) existence[/dim]...")
status.update(f"[dim]Validating user's ({username}) existence...[/dim]")
if user.exists():
console.print(
f"[bold][green]✔[/green] User ({username}) exists on GitHub[/bold]"
@@ -507,7 +506,7 @@ class Menus:
set_menu_title(menu_type="repo")
clear_screen()
if name is None or owner is None:
text_banner(text="Repo")
ascii_banner(text="Repo")
if name is None:
name = prompts.prompt(
message="GitHub Repo Name",
@@ -523,7 +522,7 @@ class Menus:
)
clear_screen()
text_banner(text=f"{owner}/{name}")
ascii_banner(text=f"{owner}/{name}")
option = q.select(
"What would you like to do/get?",
@@ -665,13 +664,13 @@ class Menus:
if option in valid_methods:
source = f"{owner}/{name}"
with Status(
status=f"[dim]Initialising repository {option}[/dim]...",
status=f"[dim]Initialising repository {option}...[/dim]",
console=console,
) as status:
repo = Repo(name=name, owner=owner)
status.update(
f"[dim]Validating repository's ({source}) existence[/dim]..."
f"[dim]Validating repository's ({source}) existence...[/dim]"
)
if repo.exists():
console.print(
@@ -698,7 +697,7 @@ class Menus:
set_menu_title(menu_type="org")
clear_screen()
if name is None:
text_banner(text="Org")
ascii_banner(text="Org")
name = prompts.prompt(
message="GitHub Organisation Name",
instruction="e.g, github",
@@ -707,7 +706,7 @@ class Menus:
)
clear_screen()
text_banner(text=name)
ascii_banner(text=name)
option = q.select(
"What would you like to do?",
@@ -781,13 +780,13 @@ class Menus:
valid_methods = self.paginated_methods | self.non_paginated_methods
if option in valid_methods:
with Status(
status=f"[dim]Initialising organisation {option}[/dim]...",
status=f"[dim]Initialising organisation {option}...[/dim]",
console=console,
) as status:
org = Org(name=name)
status.update(
f"[dim]Validating organisation's ({name}) existence[/dim]..."
f"[dim]Validating organisation's ({name}) existence...[/dim]"
)
if org.exists():
console.print(

View File

@@ -3,6 +3,8 @@ import typing as t
import questionary as q
from questionary import Style
__all__ = ["Prompts"]
class Prompts:
def __init__(self):