Skip to content

Commit

Permalink
Merge branch 'main' into multi-command-support
Browse files Browse the repository at this point in the history
  • Loading branch information
boehmseb committed Oct 7, 2024
2 parents 86a2f3e + 896716f commit 9f00712
Show file tree
Hide file tree
Showing 13 changed files with 999 additions and 949 deletions.
16 changes: 8 additions & 8 deletions .github/workflows/ci.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -14,26 +14,26 @@ jobs:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: ["3.7", "3.8", "3.9", "3.10", "3.11"]
os: [ubuntu-latest, macos-13, windows-latest]
python-version: ["3.8", "3.9", "3.10", "3.11", "3.12"]
defaults:
run:
shell: bash
steps:
- uses: actions/checkout@v3.5.2
- uses: actions/checkout@v4.1.7
- name: Install and configure Poetry
uses: snok/install-poetry@v1.3.3
uses: snok/install-poetry@v1.4.1
with:
version: 1.4.2
version: 1.8.3
virtualenvs-in-project: true
- name: Set up Python ${{ matrix.python-version }}
uses: actions/setup-python@v4.6.0
uses: actions/setup-python@v5.2.0
with:
python-version: ${{ matrix.python-version }}
architecture: x64
- name: Load cached venv
id: cached-poetry-dependencies
uses: actions/cache@v3
uses: actions/cache@v4
with:
path: .venv
key: venv-${{ runner.os }}-${{ matrix.python-version }}-${{ hashFiles('**/poetry.lock') }}
Expand All @@ -43,4 +43,4 @@ jobs:
- name: Test with pytest
run: |
source $VENV
pytest tests
pytest tests
18 changes: 15 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,7 @@ If you don't use a CLI app frequently, or there are too many options to commit t

## What does the name mean?

This project started life as a [Textual](https://github.com/Textualize/textual) experiment, which we have been giving give bird's names to.
This project started life as a [Textual](https://github.com/Textualize/textual) experiment, which we have been giving birds' names to.
A [Trogon](https://www.willmcgugan.com/blog/photography/post/costa-rica-trip-report-2017/#bird) is a beautiful bird I was lucky enough to photograph in 2017.

See also [Frogmouth](https://github.com/Textualize/frogmouth), a Markdown browser for the terminal.
Expand All @@ -90,23 +90,35 @@ pip install trogon

## Quickstart

### Click
1. Import `from trogon import tui`
2. Add the `@tui` decorator above your click app. e.g.
2. Add the `@tui` decorator above your click app, e.g.
```python
from trogon import tui

@tui()
@click.group(...)
def cli():
...
```
3. Your click app will have a new `tui` command available.

### Typer
1. Import `from trogon.typer import init_tui`
2. Pass your Typer CLI app into the `init_tui` function, e.g.
```python
cli = typer.Typer(...)
init_tui(cli)
```
3. Your Typer app will have a new `tui` command available.

See also the `examples` folder for two example apps.

## Custom command name and custom help

By default the command added will be called `tui` and the help text for it will be `Open Textual TUI.`

You can customize one or both of these using the `help=` and `command=` parameters:
You can customize one or both of these using the `command=` and `help=` parameters:

```python
@tui(command="ui", help="Open terminal UI")
Expand Down
2 changes: 1 addition & 1 deletion examples/demo.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ def cli(ctx, verbose):
help="Add labels to the task (repeatable)",
)
@click.pass_context
def add(ctx, task, priority, tags, extra):
def add(ctx, task, priority, tags, extra, category, labels):
"""Add a new task to the to-do list.
Note:
Control the output of this using the verbosity option.
Expand Down
1,666 changes: 837 additions & 829 deletions poetry.lock

Large diffs are not rendered by default.

17 changes: 11 additions & 6 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
[tool.poetry]
name = "trogon"
version = "0.5.0"
version = "0.6.0"
description = "Automatically generate a Textual TUI for your Click CLI"
authors = ["Darren Burns <[email protected]>"]
readme = "README.md"
Expand All @@ -20,23 +20,28 @@ classifiers = [
"Operating System :: POSIX :: Linux",
"Programming Language :: Python :: 3.10",
"Programming Language :: Python :: 3.11",
"Programming Language :: Python :: 3.12",
"Programming Language :: Python :: 3.8",
"Programming Language :: Python :: 3.9",
"Topic :: Software Development :: Documentation",
]

[tool.poetry.dependencies]
python = "^3.7"
textual = {version = ">=0.26.0"}
#textual = {extras = ["dev"], path = "../textual", develop = true}
python = "^3.8.1"
textual = ">=0.61.0"
click = ">=8.0.0"

typer = {version = ">=0.9.0", optional = true}

[tool.poetry.extras]
typer = ["typer"]


[tool.poetry.group.dev.dependencies]
mypy = "^1.2.0"
black = "^23.3.0"
pytest = "^7.3.1"
textual = {extras = ["dev"], version = ">=0.26.0"}
pytest = ">=8.0.0"
textual-dev = ">=1.0"

[build-system]
requires = ["poetry-core"]
Expand Down
6 changes: 3 additions & 3 deletions trogon/detect_run_string.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
import os
import shlex
import sys
from types import ModuleType


def get_orig_argv() -> list[str]:
Expand All @@ -20,10 +21,9 @@ def get_orig_argv() -> list[str]:
return argv


def detect_run_string(path=None, _main=sys.modules["__main__"]) -> str:
def detect_run_string(_main: ModuleType = sys.modules["__main__"]) -> str:
"""This is a slightly modified version of a function from Click."""
if not path:
path = sys.argv[0]
path = sys.argv[0]

# The value of __package__ indicates how Python was called. It may
# not exist if a setuptools script is installed as an egg. It may be
Expand Down
6 changes: 3 additions & 3 deletions trogon/introspect.py
Original file line number Diff line number Diff line change
Expand Up @@ -46,9 +46,9 @@ class OptionSchema:
is_flag: bool = False
is_boolean_flag: bool = False
flag_value: Any = ""
opts: list = field(default_factory=list)
opts: list[str] = field(default_factory=list)
counting: bool = False
secondary_opts: list = field(default_factory=list)
secondary_opts: list[str] = field(default_factory=list)
key: str | tuple[str] = field(default_factory=generate_unique_id)
help: str | None = None
choices: Sequence[str] | None = None
Expand Down Expand Up @@ -87,7 +87,7 @@ class CommandSchema:
@property
def path_from_root(self) -> list["CommandSchema"]:
node = self
path = [self]
path: list[CommandSchema] = [self]
while True:
node = node.parent
if node is None:
Expand Down
24 changes: 12 additions & 12 deletions trogon/run_command.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import itertools
import shlex
from collections import defaultdict
from dataclasses import dataclass
from dataclasses import dataclass, field
from typing import Any, List, Optional

from rich.text import Text
Expand Down Expand Up @@ -71,13 +71,13 @@ class UserCommandData:
"""

name: CommandName
options: List[UserOptionData]
arguments: List[UserArgumentData]
subcommand: Optional["UserCommandData"] = None
parent: Optional["UserCommandData"] = None
command_schema: Optional["CommandSchema"] = None
options: list[UserOptionData] = field(default_factory=list)
arguments: list[UserArgumentData] = field(default_factory=list)
subcommand: UserCommandData | None = None
parent: UserCommandData | None = None
command_schema: CommandSchema | None = None

def to_cli_args(self, include_root_command: bool = False) -> List[str]:
def to_cli_args(self, include_root_command: bool = False) -> list[str]:
"""
Generates a list of strings representing the CLI invocation based on the user input data.
Expand All @@ -90,11 +90,11 @@ def to_cli_args(self, include_root_command: bool = False) -> List[str]:

return cli_args

def _to_cli_args(self):
args = [self.name]
def _to_cli_args(self) -> list[str]:
args: list[str] = [self.name]

multiples = defaultdict(list)
multiples_schemas = {}
multiples: dict[str, list[tuple[str]]] = defaultdict(list)
multiples_schemas: dict[str, OptionSchema] = {}

for option in self.options:
if option.option_schema.multiple:
Expand Down Expand Up @@ -228,7 +228,7 @@ def to_cli_string(self, include_root_command: bool = False) -> Text:
"""
args = self.to_cli_args(include_root_command=include_root_command)

text_renderables = []
text_renderables: list[Text] = []
for arg in args:
text_renderables.append(
Text(shlex.quote(str(arg)))
Expand Down
Loading

0 comments on commit 9f00712

Please sign in to comment.