Skip to content

Commit

Permalink
chore: ewels#25 add unit test using rich click examples
Browse files Browse the repository at this point in the history
  • Loading branch information
BrutalSimplicity committed Oct 23, 2022
1 parent 3139f79 commit a594c1e
Show file tree
Hide file tree
Showing 26 changed files with 1,122 additions and 4 deletions.
29 changes: 26 additions & 3 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -1,17 +1,40 @@
[tool.black]
line-length=120
target-version=['py37']
line-length = 120
target-version = ['py37']

[tool.isort]
line_length = 120
multi_line_output = 3
force_alphabetical_sort_within_sections = "True"
force_sort_within_sections = "False"
known_richclick = ["rich_click"]
sections=["FUTURE", "STDLIB", "THIRDPARTY", "FIRSTPARTY", "LOCALFOLDER", "RICHCLICK"]
sections = [
"FUTURE",
"STDLIB",
"THIRDPARTY",
"FIRSTPARTY",
"LOCALFOLDER",
"RICHCLICK",
]
profile = "black"

[tool.mypy]
python_version = "3.7"
ignore_missing_imports = "True"
scripts_are_modules = "True"

[tool.pyright]
include = ["src"]
pythonVersion = "3.7"
typeCheckingMode = "basic"
executionEnvironments = [
{ root = "src" },
{ root = "tests", extra_paths = [
"src",
] },
]

[tool.pytest.ini_options]
addopts = "-s -rP -vv --showlocals"
pythonpath = ["tests", "src"]
testpaths = ["tests"]
2 changes: 1 addition & 1 deletion setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,6 @@
"importlib-metadata; python_version < '3.8'",
],
extras_require={
"dev": "pre-commit",
"dev": ["pre-commit", "pytest", "typing_extensions"],
},
)
58 changes: 58 additions & 0 deletions tests/conftest.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
import os
from pathlib import Path
from typing import Any, Callable

import pytest
from click.testing import CliRunner, Result
from typing_extensions import Protocol


@pytest.fixture
def root_dir():
return Path(__file__).parent


@pytest.fixture
def fixtures_dir():
return Path(__file__).parent / "fixtures"


@pytest.fixture
def tmpdir(root_dir: Path):
tmpdir = root_dir / "tmp"
tmpdir.mkdir(parents=True, exist_ok=True)
return tmpdir


@pytest.fixture
def assert_str(request: pytest.FixtureRequest, tmpdir: Path):
def assertion(actual: str, expected: str):
normalized_expected = [line.strip() for line in expected.strip().splitlines() if line.strip()]
normalized_actual = [line.strip() for line in actual.strip().splitlines() if line.strip()]

try:
assert normalized_expected == normalized_actual
except Exception:
tmppath = tmpdir / f"{request.node.name}.out"
tmppath.write_text(actual.strip())
raise

return assertion


class InvokeCli(Protocol):
def __call__(self, cmd: Callable[..., Any], *args: str) -> Result:
...


@pytest.fixture
def invoke():
runner = CliRunner()

def invoke(cmd, *args, **kwargs):
result = runner.invoke(cmd, *args, **kwargs, standalone_mode=False)
if result.exception:
raise result.exception
return result

return invoke
33 changes: 33 additions & 0 deletions tests/fixtures/arguments.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import rich_click as click

# Show the positional arguments
click.rich_click.SHOW_ARGUMENTS = True
# Uncomment this line to group the arguments together with the options
# click.rich_click.GROUP_ARGUMENTS_OPTIONS = True


@click.command()
@click.argument("input", type=click.Path(), required=True)
@click.option(
"--type",
default="files",
show_default=True,
help="Type of file to sync",
)
@click.option("--all", is_flag=True, help="Sync all the things?")
@click.option("--debug", is_flag=True, help="Enable debug mode")
def cli(input, type, all, debug):
"""
My amazing tool does all the things.
This is a minimal example based on documentation
from the 'click' package.
You can try using --help at the top level and also for
specific group subcommands.
"""
print(f"Debug mode is {'on' if debug else 'off'}")


if __name__ == "__main__":
cli()
33 changes: 33 additions & 0 deletions tests/fixtures/custom_errors.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import rich_click as click

# Show custom error messages
click.rich_click.STYLE_ERRORS_SUGGESTION = "magenta italic"
click.rich_click.ERRORS_SUGGESTION = "Try running the '--help' flag for more information."
click.rich_click.ERRORS_EPILOGUE = "To find out more, visit [link=https://mytool.com]https://mytool.com[/link]"


@click.command()
@click.argument("input", type=click.Path(), required=True)
@click.option(
"--type",
default="files",
show_default=True,
help="Type of file to sync",
)
@click.option("--all", is_flag=True, help="Sync all the things?")
@click.option("--debug", is_flag=True, default=False, help="Enable debug mode")
def cli(input, type, all, debug):
"""
My amazing tool does all the things.
This is a minimal example based on documentation
from the 'click' package.
You can try using --help at the top level and also for
specific group subcommands.
"""
print(f"Debug mode is {'on' if debug else 'off'}")


if __name__ == "__main__":
cli()
28 changes: 28 additions & 0 deletions tests/fixtures/declarative.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import click

from rich_click import RichCommand, RichGroup


@click.group(cls=RichGroup)
@click.option("--debug/--no-debug", default=False)
def cli(debug):
"""
My amazing tool does all the things.
This is a minimal example based on documentation
from the 'click' package.
You can try using --help at the top level and also for
specific group subcommands.
"""
click.echo(f"Debug mode is {'on' if debug else 'off'}")


@cli.command(cls=RichCommand)
def sync():
"""Synchronise all your files between two places."""
click.echo("Syncing")


if __name__ == "__main__":
cli()
37 changes: 37 additions & 0 deletions tests/fixtures/envvar.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
import rich_click as click

# import click

# Example test usage:
# GREETER_DEBUG=1 GREETER_GREET_USERNAME="test" EMAIL_ADDRESS="foo@bar.com" python examples/09_envvar.py greet


@click.group()
@click.option("--debug/--no-debug")
def cli(debug):
click.echo(f"Debug mode is {'on' if debug else 'off'}")


@cli.command()
@click.option("--username", help="This can be set via env var GREETER_GREET_USERNAME", show_envvar=True)
@click.option(
"--nickname",
envvar="NICKNAME",
show_envvar=True,
show_default=True,
help="This can be set via env var NICKNAME",
)
@click.option(
"--email",
envvar=["EMAIL", "EMAIL_ADDRESS"],
show_envvar=True,
default="foo@bar.com",
show_default=True,
help="This can be set via env var EMAIL or EMAIL_ADDRESS",
)
def greet(username, nickname, email):
click.echo(f"Hello {username} ({nickname}) with email {email}!")


if __name__ == "__main__":
cli(auto_envvar_prefix="GREETER")
102 changes: 102 additions & 0 deletions tests/fixtures/groups_sorting.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,102 @@
import rich_click as click

click.rich_click.OPTION_GROUPS = {
"03_groups_sorting.py": [
{
"name": "Basic usage",
"options": ["--type", "--output"],
},
{
"name": "Advanced options",
"options": ["--help", "--version", "--debug"],
# You can also set table styles at group-level instead of using globals if you want
"table_styles": {
"row_styles": ["bold", "yellow", "cyan"],
},
},
],
"03_groups_sorting.py sync": [
{
"name": "Inputs and outputs",
"options": ["--input", "--output"],
},
{
"name": "Advanced usage",
"options": ["--overwrite", "--all", "--help"],
},
],
}
click.rich_click.COMMAND_GROUPS = {
"03_groups_sorting.py": [
{
"name": "Main usage",
"commands": ["sync", "download"],
},
{
"name": "Configuration",
"commands": ["config", "auth"],
},
]
}


@click.group(context_settings=dict(help_option_names=["-h", "--help"]))
@click.option(
"--type",
default="files",
show_default=True,
required=True,
help="Type of file to sync",
)
@click.option(
"--debug/--no-debug",
"-d/-n",
default=False,
show_default=True,
help="Show the debug log messages",
)
@click.version_option("1.23", prog_name="mytool")
def cli(type, debug):
"""
My amazing tool does all the things.
This is a minimal example based on documentation
from the 'click' package.
You can try using --help at the top level and also for
specific subcommands.
"""
print(f"Debug mode is {'on' if debug else 'off'}")


@cli.command()
@click.option("--input", "-i", required=True, help="Input path")
@click.option("--output", "-o", help="Output path")
@click.option("--all", is_flag=True, help="Sync all the things?")
@click.option("--overwrite", is_flag=True, help="Overwrite local files")
def sync(input, output, all, overwrite):
"""Synchronise all your files between two places."""
print("Syncing")


@cli.command()
@click.option("--all", is_flag=True, help="Get everything")
def download(all):
"""Pretend to download some files from somewhere."""
print("Downloading")


@cli.command()
def auth():
"""Authenticate the app."""
print("Downloading")


@cli.command()
def config():
"""Set up the configuration."""
print("Downloading")


if __name__ == "__main__":
cli()
36 changes: 36 additions & 0 deletions tests/fixtures/markdown.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import rich_click as click

# Use Markdown (bit of a ridiculous example!)
click.rich_click.USE_MARKDOWN = True


@click.command()
@click.option(
"--input",
type=click.Path(),
help="Input **file**. _[default: a custom default]_",
)
@click.option(
"--type",
default="files",
show_default=True,
help="Type of file to sync",
)
@click.option("--all", is_flag=True, help="Sync\n 1. all\n 2. the\n 3. things?")
@click.option("--debug", is_flag=True, help="# Enable `debug mode`")
def cli(input, type, all, debug):
"""
My amazing tool does _**all the things**_.
This is a `minimal example` based on documentation from the [_click_ package](https://click.palletsprojects.com/).
> Remember:
> - You can try using --help at the top level
> - Also for specific group subcommands.
"""
print(f"Debug mode is {'on' if debug else 'off'}")


if __name__ == "__main__":
cli()
Loading

0 comments on commit a594c1e

Please sign in to comment.