Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
20 commits
Select commit Hold shift + click to select a range
8986e2f
feat: :sparkles: Include several approaches of improving the CLI
joelostblom Feb 20, 2026
ef2a603
fix: :bug: Clean up to only keep the current suggestion
joelostblom Feb 20, 2026
52882f5
feat: :sparkles: Show default value also for `None`
joelostblom Feb 20, 2026
c9251ff
refactor: :recycle: Use functional style
joelostblom Feb 23, 2026
314dbff
docs: :memo: Explain need for sorting
joelostblom Feb 23, 2026
8df5e66
test: :white_check_mark: Avoid testing private modules
joelostblom Feb 23, 2026
a5ea441
Merge branch 'main' into feat/beautify-cli-help
lwjohnst86 Feb 24, 2026
4360ed7
Apply suggestions from code review
joelostblom Feb 24, 2026
824bdd7
chore(pre-commit): :pencil2: automatic fixes
pre-commit-ci[bot] Feb 24, 2026
bb4c41d
test: :white_check_mark: Remove coverage config
joelostblom Feb 24, 2026
b5ae897
fix: :bug: Uuse more descriptive variable name
joelostblom Feb 24, 2026
f4c70c2
Merge branch 'main' into feat/beautify-cli-help
lwjohnst86 Feb 24, 2026
206d742
Apply suggestion from @joelostblom
joelostblom Feb 24, 2026
7d94a3a
Merge branch 'main' into feat/beautify-cli-help
lwjohnst86 Feb 25, 2026
ad65ac8
docs: 📝 Reformat as per just run all
joelostblom Mar 2, 2026
775eeae
Merge branch 'main' into feat/beautify-cli-help
joelostblom Mar 2, 2026
4aff1f8
test: ✅ Reformat test strings to match new help format
joelostblom Mar 2, 2026
79cfe34
test: ✅ Test color output in help message
joelostblom Mar 2, 2026
5e1f4f3
chore(pre-commit): :pencil2: automatic fixes
pre-commit-ci[bot] Mar 2, 2026
87f1a1a
chore: 🔧 Restore unintended formatting changes
joelostblom Mar 2, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions src/seedcase_flower/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,14 +4,27 @@
from typing import Any, Optional

from cyclopts import App, Parameter, config
from cyclopts.help import ColumnSpec, DefaultFormatter, DescriptionRenderer

# from seedcase_flower.config import Config as FlowerConfig
from seedcase_flower.internals import BuildStyle, Uri, _parse_uri, _read_properties
from seedcase_flower.internals import (
BuildStyle,
Uri,
_format_param_help,
_parse_uri,
_read_properties,
)

app = App(
name="seedcase-flower",
help="Flower generates human-readable documentation from Data Packages.",
default_parameter=Parameter(negative=()),
help_formatter=DefaultFormatter(
column_specs=(
ColumnSpec(renderer=_format_param_help),
ColumnSpec(renderer=DescriptionRenderer(newline_metadata=True)),
)
),
default_parameter=Parameter(negative=(), show_default=True),
config=[
config.Toml(
".flower.toml",
Expand Down
26 changes: 25 additions & 1 deletion src/seedcase_flower/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,14 @@
import json
from dataclasses import dataclass
from enum import Enum
from itertools import repeat
from pathlib import Path
from typing import Any
from urllib import parse

from cyclopts.annotations import get_hint_name
from cyclopts.help import HelpEntry


class BuildStyle(Enum):
"""Built-in styles for outputting to file."""
Expand Down Expand Up @@ -66,7 +70,27 @@ def _convert_to_github_uri(split_gh_uri: parse.SplitResult) -> Uri:
)


# TODO Extend to also read properties from URLs
def _format_param_help(entry: HelpEntry) -> str:
"""Re-structure the parameter help into a more readable format."""
# Sort to put the flag first (eg `--uri URI` instead of the default `URI --uri`)
names = map(_add_highlight_syntax, sorted(entry.names), repeat(entry.type))
return f"{' '.join(names)}".strip()


def _add_highlight_syntax(name: str, entry_type: type | None) -> str:
"""Add markup character to highlight in colors, etc where desired."""
formatted_name = f"[bold cyan]{name}[/bold cyan]"
if not name.startswith("-"):
# Matching the `dim` used by default in cyclopts for `choices` and
# `defaults` in the description
formatted_name = f"[dim]<{name}>[/dim]"

# Don't output redundant value placeholder for boolean flags
if get_hint_name(entry_type) == "bool":
formatted_name = ""
return formatted_name


def _read_properties(uri: Uri) -> dict[str, Any]:
if uri.local:
path = Path(parse.urlsplit(uri.value).path)
Expand Down
72 changes: 51 additions & 21 deletions tests/test_cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -108,9 +108,9 @@ def test_build_reads_uri_from_flower_toml(tmp_path, monkeypatch):
Flower generates human-readable documentation from Data Packages.

╭─ Commands ─────────────────────────────────────────────────────────────────────────────╮
│ build Build human-readable documentation from a datapackage.json file. │
│ --help (-h) Display this message and exit. │
│ --version Display application version. │
<build> Build human-readable documentation from a datapackage.json file.
│ --help Display this message and exit.
│ --version Display application version.
╰────────────────────────────────────────────────────────────────────────────────────────╯
""" # noqa
)
Expand All @@ -122,24 +122,27 @@ def test_build_reads_uri_from_flower_toml(tmp_path, monkeypatch):
Build human-readable documentation from a datapackage.json file.

╭─ Parameters ───────────────────────────────────────────────────────────────────────────╮
│ URI --uri The path to a local datapackage.json file or its parent │
│ folder. Can also be an https: URL to a remote │
│ datapackage.json or a github: / gh: URI pointing to a │
│ repo with a datapackage.json in the repo root (in the │
│ format gh:org/repo, which can also include reference to a │
│ tag or branch, such as gh:org/repo@main or │
│ `gh:org/repo@1.0.1). [default: datapackage.json] │
│ STYLE --style The style used to structure the output. If a template │
│ directory is given, this parameter will be ignored. │
│ [choices: quarto-one-page, quarto-resource-listing, │
│ quarto-resource-tables] [default: quarto-one-page] │
│ TEMPLATE-DIR --template-dir The directory that contains the Jinja template files and │
│ sections.toml. When set, it will override any built-in │
│ style given by the style parameter. │
│ OUTPUT-DIR --output-dir The directory to save the generated files in. [default: │
│ docs] │
│ VERBOSE --verbose If True, prints additional information to the console. │
│ [default: False] │
│ --uri <URI> The path to a local datapackage.json file or its parent │
│ folder. Can also be an https: URL to a remote │
│ datapackage.json or a github: / gh: URI pointing to a │
│ repo with a datapackage.json in the repo root (in the │
│ format gh:org/repo, which can also include reference to │
│ a tag or branch, such as gh:org/repo@main or │
│ `gh:org/repo@1.0.1). │
│ [default: datapackage.json] │
│ --style <STYLE> The style used to structure the output. If a template │
│ directory is given, this parameter will be ignored. │
│ [choices: quarto-one-page, quarto-resource-listing, │
│ quarto-resource-tables] │
│ [default: quarto-one-page] │
│ --template-dir <TEMPLATE-DIR> The directory that contains the Jinja template files │
│ and sections.toml. When set, it will override any │
│ built-in style given by the style parameter. │
│ [default: None] │
│ --output-dir <OUTPUT-DIR> The directory to save the generated files in. │
│ [default: docs] │
│ --verbose If True, prints additional information to the console. │
│ [default: False] │
╰────────────────────────────────────────────────────────────────────────────────────────╯
""" # noqa
)
Expand Down Expand Up @@ -177,6 +180,33 @@ def test_build_help_page(capsys, console):
assert capsys.readouterr().out == _BUILD_HELP_PAGE, _CHANGED_MSG.format(cmd="build")


# It was not possible to include these color markup tags directly in the help string
# test above because printing them out explicitly in the rich console messes up the
# column widths in cyclopts
def test_build_help_page_applies_rich_markup(capsys):
"""build --help should apply bold-cyan to flags and dim to placeholders."""
from rich.console import Console

markup_console = Console(
width=90,
force_terminal=False,
highlight=False,
color_system=None,
markup=False,
legacy_windows=False,
)
with pytest.raises(SystemExit):
app(["build", "--help"], console=markup_console)
output = capsys.readouterr().out
assert "[bold cyan]--uri[/bold cyan]" in output
assert "[dim]<URI>[/dim]" in output
assert "[bold cyan]--style[/bold cyan]" in output
assert "[dim]<STYLE>[/dim]" in output
assert "[bold cyan]--verbose[/bold cyan]" in output
# Boolean flags must not produce a positional placeholder
assert "[dim]<verbose>[/dim]" not in output


# view (placeholder) ====


Expand Down