Skip to content
Open
Show file tree
Hide file tree
Changes from 7 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
2 changes: 2 additions & 0 deletions .coveragerc
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
[run]
omit = src/seedcase_flower/internals.py
Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This excludes our private code from the coverage percentage. I remember we mentioned before that we only test public facing code (and implicitly the private code as it is used in the public facing code). I don't know if we want it formal through a change like this but I'm including it as a suggestion since this PR fails coverage without it (could be made its own PR).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not sure I understand. Is that because the code you're adding isn't used when running via tests, so doesn't get picked up by the coverage?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I'm unsure how to test this since there is no public function calling this code. It is only used during the initialization of app, should we create a test for app --help which compares the output help string to a fixed test case? It seems a bit wonky, but that the public facing component is correct formatting of the help message.

It would be easier to test the private function directly, but then there could be a gap to what we think is the correct behavior and what actually makes the help message look the way it should.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmmm, I think for now, it's fine to keep it in the coverage percent. It truthfully shows that not all code has been covered, which is true! 😛 So you can delete this file ☺️

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sounds good, removed!

16 changes: 14 additions & 2 deletions src/seedcase_flower/cli.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,25 @@
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, _read_properties, _resolve_uri
from seedcase_flower.internals import (
BuildStyle,
_format_param_help,
_read_properties,
_resolve_uri,
)

app = App(
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
27 changes: 27 additions & 0 deletions src/seedcase_flower/internals.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,13 @@

import json
from enum import Enum
from itertools import repeat
from pathlib import Path
from typing import Any

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


class BuildStyle(Enum):
"""Built-in styles for outputting to file."""
Expand All @@ -26,3 +30,26 @@ def _read_properties(path: Path) -> dict[str, Any]:
with open(path) as properties_file:
datapackage: dict[str, Any] = json.load(properties_file)
return datapackage


def _format_param_help(entry: HelpEntry) -> str:
"""Re-structure the parameter help into a more readable format."""
if entry.names:
# 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."""
if not name.startswith("-"):
# Don't output redundant value placeholder for boolean flags
if get_hint_name(entry_type) == "bool":
name = ""
else:
# Matching the `dim` used by default in cyclopts for `choices` and
# `defaults` in the description
name = f"[dim]<{name}>[/dim]"
else:
name = f"[bold cyan]{name}[/bold cyan]"
return name