{"id":46857346,"url":"https://github.com/dim-gggl/yotta","last_synced_at":"2026-03-10T17:28:04.149Z","repository":{"id":327093472,"uuid":"1107837604","full_name":"dim-gggl/yotta","owner":"dim-gggl","description":"A Python framework for CLI tools projects","archived":false,"fork":false,"pushed_at":"2026-03-08T13:19:39.000Z","size":599,"stargazers_count":1,"open_issues_count":4,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-03-08T14:45:11.078Z","etag":null,"topics":["cli","click","framework","python","rich","rich-click"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dim-gggl.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2025-12-01T17:15:51.000Z","updated_at":"2026-03-08T13:19:42.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/dim-gggl/yotta","commit_stats":null,"previous_names":["dim-gggl/yotta"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dim-gggl/yotta","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dim-gggl%2Fyotta","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dim-gggl%2Fyotta/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dim-gggl%2Fyotta/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dim-gggl%2Fyotta/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dim-gggl","download_url":"https://codeload.github.com/dim-gggl/yotta/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dim-gggl%2Fyotta/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":30278371,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-03-08T20:45:49.896Z","status":"ssl_error","status_checked_at":"2026-03-08T20:45:49.525Z","response_time":56,"last_error":"SSL_connect returned=1 errno=0 peeraddr=140.82.121.6:443 state=error: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cli","click","framework","python","rich","rich-click"],"created_at":"2026-03-10T17:28:03.117Z","updated_at":"2026-03-10T17:28:04.136Z","avatar_url":"https://github.com/dim-gggl.png","language":"Python","readme":"# \u003cdiv align=\"center\"\u003eyotta\n\n\u003cdiv align=\"center\"\u003e\n    \u003ca href=\"https://www.python.org/\"\u003e\n      \u003cimg alt=\"Python Badge\" src=\"https://img.shields.io/badge/python-3.10%2B-blue?style=plastic\u0026logo=python\u0026logoColor=yellow\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://docs.astral.sh/uv/\"\u003e\n      \u003cimg alt=\"uv Badge\" src=\"https://img.shields.io/endpoint?url=https://raw.githubusercontent.com/astral-sh/uv/main/assets/badge/v0.json\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://rich.readthedocs.io/en/stable/index.html\"\u003e\n      \u003cimg alt=\"Static Badge\" src=\"https://img.shields.io/badge/rich-14.3.3%2B-%238b36db\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://click.palletsprojects.com/en/stable/\"\u003e\n      \u003cimg alt=\"Static Badge\" src=\"https://img.shields.io/badge/click-8.3.1%2B-%23cea3c7?style=plastic\u0026logo=click\u0026logoColor=%23cea3c7\"\u003e\n    \u003c/a\u003e\n    \u003ca href=\"https://pypi.org/project/rich-click/\"\u003e\n      \u003cimg alt=\"Yes Yotta Badge\" class=\"\" src=\"https://img.shields.io/badge/rich--click-1.9.7%2B-%23800000?style=plastic\u0026logo=rich-click\u0026logoColor=%23800000\"\u003e\n    \u003c/a\u003e\n\u003c/div\u003e\n\n![](https://raw.githubusercontent.com/dim-gggl/yotta/main/media/yotta_dark.svg)\n\nBuild complete CLIs and TUIs in Python, the fast way. (Django-inspired)\n\nyotta is designed to simplify the creation of Command Line Interfaces (CLI) and Terminal User Interfaces (TUI).\n\nIt combines the robustness of Click, the beauty of Rich, and the interactivity of Textual within a modular architecture inspired by Django.\n\n## Why yotta?\n\nMost CLI applications follow the same foundational patterns. yotta packages those patterns into a framework so you can ship faster without giving up structure, readability, or user experience.\n\nBuilding a CLI app with yotta is making sure to get:\n- Modular Architecture: Split your code into reusable \"Apps\" (startproject, startapp).\n- UI-First Spirit: A native UX engine. Display tables, spinners, and alerts without manually importing Rich.\n- Hybrid TUI Mode: Transform a command into a full interactive dashboard (mouse/keyboard) via native Textual integration.\n- Smart Arguments: Automatic validation (Email, Files, Ranges) before your code even runs.\n\n## Installation\n\n### Install the CLI from PyPI\n\nUse a global tool install if you want the `yotta` command available everywhere:\n\n```bash\nuv tool install yotta-framework\nyotta --version\n```\n\n### Add yotta to a project\n\nIf you want to use yotta inside an existing project managed by `uv`:\n\n```bash\nuv add yotta-framework\n```\n\n### Development setup\n\nIf you want to work on yotta itself:\n\n```bash\ngit clone https://github.com/dim-gggl/yotta.git\ncd yotta\nuv sync --all-extras\nuv pip install -e .\n```\n## Quick Start\n\n1. Create a new project\n\nyotta scaffolds the entire folder structure for you.\n```bash\nyotta startproject my_cli\ncd my_cli\nuv sync\n# A pyproject.toml and .env.example (with YOTTA_SETTINGS_MODULE) are created for you\n```\n2. Create an app (module)\n```bash\nuv run ./manage.py startapp inventory\n```\n\u003e Note: Don't forget to add 'my_cli.inventory' (replace with your project name) to INSTALLED_APPS in your settings.py file.\n3. Scaffold a command interactively (optional)\n```bash\nuv run ./manage.py startcommand\n```\nFollow the prompts to pick the target app, command name, arguments, and options. yotta will append a ready-to-edit function to the selected app's `commands.py`.\n4. Write your first command\nIn `my_cli/inventory/commands.py`:\n```python\nimport time\n\nfrom yotta.cli.decorators import command, argument\nfrom yotta.core.context import YottaContext\nfrom yotta.core.types import EMAIL\n\n\n@command(name=\"add_user\", help=\"Adds a user to the inventory\")\n@argument(\"email\", type=EMAIL)\ndef add_user(yotta: YottaContext, email: str) -\u003e None:\n    # Using the native UI engine\n    yotta.ui.header(\"New User\")\n    # Access project configuration without extra imports\n    # (settings are loaded lazily on first attribute access)\n    _ = yotta.settings\n\n    with yotta.ui.spinner(\"Checking database...\"):\n        # Simulate work\n        time.sleep(1)\n\n    yotta.ui.success(f\"User [bold]{email}[/] added successfully!\")\n\n    # Automatic formatted table\n    yotta.ui.table(\n        columns=[\"ID\", \"Email\", \"Status\"],\n        rows=[[\"1\", email, \"Active\"]],\n        title=\"Summary\",\n    )\n```\n5. Run the command\n```bash\nuv run ./manage.py add_user contact@example.com\n```\n\n### Settings and environment\n- `YOTTA_SETTINGS_MODULE` is loaded from `.env` or `.env.local` (the latter overrides).\n- You can also set `YOTTA_ENV=prod` to auto-load `settings_prod.py`.\n- `YOTTA_DEBUG=1` will surface full tracebacks during settings import and loader errors.\n- `THEME` controls the console palette. Supported values: `\"default\"`, `\"dark\"` (unknown values fall back to `\"default\"`).\n\nTo override the theme, set it in your project's `settings.py`:\n\n```python\n# settings.py\nTHEME = \"dark\"\n```\n\n### Debugging imports and discovery\n- Loader warnings surface when an app has no `commands.py`; use `--verbose` for extra details or `--quiet` to silence.\n- Use `--strict` to fail fast on missing/broken command modules (useful in CI).\n\n## TUI Mode (Textual Integration)\nNeed a real-time interactive dashboard? yotta integrates Textual natively.\n\nDefine a view in `my_cli/inventory/ui.py`:\n```python\nfrom textual.app import ComposeResult\nfrom textual.widgets import Placeholder\nfrom yotta.ui.tui import YottaApp\n\n\nclass MonitorDashboard(YottaApp):\n    def compose(self) -\u003e ComposeResult:\n        yield Placeholder(\"Performance charts here\")\n\n```\nLaunch it from a standard command:\n```python\nfrom yotta.cli.decorators import command\nfrom yotta.core.context import YottaContext\n\n\n@command(name=\"monitor\")\ndef launch_monitor(yotta: YottaContext) -\u003e None:\n    app = MonitorDashboard(title=\"Super Monitor\")\n    app.run()\n\n```\n## Key Features\n### The UI Context (yotta.ui)\n\nyotta injects a ui wrapper into all your commands. No need to instantiate Console everywhere.\n\n|Method|Description|\n|:--|:--|\n|`yotta.ui.header(title, subtitle)`|Displays a stylized panel header.|\n|`yotta.ui.success(msg)`|Displays a success message (green).|\n|`yotta.ui.error(msg)`|Displays an error message (red).|\n|`yotta.ui.table(cols, rows)`|Generates a formatted Rich table.|\n|`yotta.ui.spinner(msg)`|Context manager for an animated loader.|\n|`yotta.ui.confirm(question)`|Interactive Yes/No prompt.|\n\n### RichUI - Unified Access to All Rich Components\n\nNeed direct access to Rich components? Use the `rich` singleton to instantiate any Rich component without manual imports.\n\n```python\nfrom yotta.ui import rich\n\n# Instead of: from rich.align import Align\nalign = rich.align(\"Centered text\", align=\"center\")\n\n# Instead of: from rich.syntax import Syntax\nsyntax = rich.syntax(code, \"python\", theme=\"monokai\")\n\n# Instead of: from rich.table import Table\ntable = rich.table(title=\"My Data\")\n\n# Instead of: from rich.tree import Tree\ntree = rich.tree(\"Root\")\n\n# Instead of: from rich.panel import Panel\npanel = rich.panel(\"Content\", title=\"Info\")\n```\n\n**Available components and utilities:**\n\n- **Core:** console, group\n- **Layout:** align, columns, constrain, layout, padding\n- **Containers:** panel\n- **Text \u0026 Styling:** color, emoji, pretty, style, styled, syntax, text, theme, markdown\n- **Tables \u0026 Trees:** table, tree\n- **Progress:** progress, spinner, status, live (with bar_column, text_column, etc.)\n- **Prompts:** prompt, confirm, int_prompt, float_prompt\n- **Rendering:** rule, segment, traceback, json\n- **Utilities:** pprint, pretty_repr, install_traceback, escape_markup, render_markup\n\n**Box styles:** Access via `rich.ROUNDED`, `rich.HEAVY`, `rich.DOUBLE`, `rich.MINIMAL`\n\nThis singleton approach provides seamless access to all Rich functionality through a single import, keeping your code clean and consistent.\n\n### Smart Types (yotta.core.types)\n\nValidate user input without writing a single if/else.\n\n`EMAIL`: Validates email format (Regex).\n\n`File(extension='.json')`: Checks for file existence AND specific extension.\n\n`Range(min=18, max=99)`: Enforces numeric range.\n\n`Choice([...])`: Restrict values to a predefined list (case-insensitive by default).\n\n`Path() / Directory()`: Validate existing filesystem paths (files or directories).\n\n`UUID()`: Validate UUID strings.\n\n`URL()`: Validate http/https URLs.\n\n`JSON()`: Accept JSON strings or paths to JSON files, returns parsed objects.\n\n`Port(min,max)`: Validate port numbers in the allowed range.\n\n`EnumChoice(MyEnum)`: Use Python Enums as a source of allowed values.\n\n## Project Structure\n```\nmy_cli/\n├── .env.example           # Environment bootstrap\n├── manage.py              # Project entry point\n├── pyproject.toml         # Project metadata and dependencies\n├── settings.py            # Global configuration\n└── my_cli/                # Your applications folder (as a package)\n    ├── main/\n    │   ├── __init__.py\n    │   └── commands.py    # Example command created by startproject\n    └── inventory/\n        ├── __init__.py\n        ├── commands.py    # Your CLI commands\n        └── ui.py          # Your visual components\n```\n","funding_links":[],"categories":[],"sub_categories":[],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdim-gggl%2Fyotta","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdim-gggl%2Fyotta","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdim-gggl%2Fyotta/lists"}