Skip to content

Commit

Permalink
Merge pull request #2 from adammillerio/pr2
Browse files Browse the repository at this point in the history
add tests and development docs
  • Loading branch information
adammillerio authored May 21, 2024
2 parents f671e5b + e4a6ae2 commit 54be3a7
Show file tree
Hide file tree
Showing 5 changed files with 221 additions and 7 deletions.
3 changes: 2 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.DS_Store
__pycache__
click_tree.egg-info
dist
dist
.pyre
10 changes: 10 additions & 0 deletions .pyre_configuration
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
{
"site_package_search_strategy": "all",
"source_directories": [
"."
],
"exclude": [
".*\/.sl\/.*"
],
"strict": true
}
54 changes: 50 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,10 @@ home - home automation (hass-cli)
This library uses [anytree](https://anytree.readthedocs.io/en/stable/index.html)
for constructing and rendering the tree.

The original inspiration for this tree implementation was based off of the
[click-command-tree](https://github.com/whwright/click-command-tree) library
created by Harrison Wright.

# Usage

## Parameter
Expand Down Expand Up @@ -113,8 +117,50 @@ style: Optional[AbstractStyle]. Override the anytree style used to render
For manual implementation, the `ignore_names` and `style` parameters can be
provided to `tree.render()`.

# Credits
# Development

The original inspiration for this tree implementation was based off of the
[click-command-tree](https://github.com/whwright/click-command-tree) library
created by Harrison Wright.
Install in development mode:
```bash
pip3 install -e '.[dev]'
```

## Type Checking

Ensure no type errors are present with [pyre](https://github.com/facebook/pyre-check):

```bash
pyre check
ƛ No type errors found
```

## Formatting

Format code with the [black](https://github.com/psf/black) formatter:

```bash
black click_tree
All done! ✨ 🍰 ✨
```

## Testing

Ensure tests pass with [TestSlide](https://github.com/facebook/TestSlide):

```bash
cd test
testslide test_click_tree.py
test_click_tree.ClickTreeTests
test_click_tree
test_click_tree_param
test_click_tree_param_not_bool
test_click_tree_param_not_called
test_click_tree_render
test_click_tree_scoped
--_ |""---__
Executed 6 examples in 0.1s: |'.| || . """|
Successful: 6 | || || /|\""-. |
Failed: 0 | || || | | |
Skipped: 0 | || || | \|/ |
Not executed: 0 |."| || --"" '__|
https://testslide.readthedocs.io/
```
5 changes: 3 additions & 2 deletions setup.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@
download_url="https://github.com/adammillerio/click-tree/archive/v0.0.1.tar.gz",
keywords=[],
classifiers=[
"Development Status :: 5 - Production",
"Intended Audience :: End Users/Desktop",
"Development Status :: 5 - Production/Stable",
"Intended Audience :: Developers",
"License :: OSI Approved :: MIT License",
"Programming Language :: Python :: 3",
"Programming Language :: Python :: 3.10",
Expand All @@ -27,4 +27,5 @@
"anytree",
"click",
],
extras_require={"dev": ["black", "pyre-check", "testslide"]},
)
156 changes: 156 additions & 0 deletions test/test_click_tree.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,156 @@
#!/usr/bin/env python3
from inspect import cleandoc
from typing import Any, Optional

from click_tree import __name__ as _BASE, ClickTreeParam, ClickNode, get_tree

from anytree.exporter import DictExporter
import click
from click.testing import CliRunner
from testslide import TestCase


class ClickTreeTests(TestCase):
def setUp(self) -> None:
@click.group("tree_test", short_help="test the click tree")
@click.option(
"--tree",
is_flag=True,
type=ClickTreeParam(scoped=True, ignore_names=["smn-run"]),
help="Enable tree display.",
)
@click.pass_context
def tree_test_click(click_ctx: click.Context, tree: Optional[bool]) -> None:
pass

@tree_test_click.command("root_command", help="a root command")
def root_command_click() -> None:
pass

@tree_test_click.group("root_group", short_help="a root group")
def root_group_click() -> None:
pass

@root_group_click.group(
"sub_group",
short_help="a sub group",
)
def sub_group_click() -> None:
pass

@sub_group_click.command(
"default_command", help="default command of the sub group"
)
def default_command_click() -> None:
pass

# This "simulates" ClickTree's interactions with DefaultGroup without
# requiring it to be present in this repo.
sub_group_click.default_cmd_name = "default_command"

@sub_group_click.command(
"other_command", help="another command of the sub group"
)
def other_command_click() -> None:
pass

sub_group = ClickNode(name="sub_group", description="a sub group")
sub_group.children = (
ClickNode(
name="default_command",
description="default command of the sub group",
default_command=True,
parent=sub_group,
),
ClickNode(
name="other_command",
description="another command of the sub group",
parent=sub_group,
),
)

root = ClickNode(name="tree_test", description="test the click tree")

root_group = ClickNode(
name="root_group", description="a root group", parent=root
)
root_group.children = (sub_group,)

root.children = (
ClickNode(name="root_command", description="a root command", parent=root),
root_group,
)

self.click_root = tree_test_click
self.expected_tree = root

self.exporter = DictExporter()
self.runner = CliRunner()

def test_click_tree(self) -> None:
tree = get_tree(self.click_root)

self.assertEqual(
self.exporter.export(tree), self.exporter.export(self.expected_tree)
)

def test_click_tree_scoped(self) -> None:
argv = ["/some/fake/path", "--tree", "root_group", "--some-arg", "sub_group"]
tree = get_tree(self.click_root, argv)

root_group = next(
child for child in self.expected_tree.children if child.name == "root_group"
)
sub_group = next(
child for child in root_group.children if child.name == "sub_group"
)

self.assertEqual(self.exporter.export(tree), self.exporter.export(sub_group))

def test_click_tree_render(self) -> None:
expected_stdout = cleandoc(
"""\
tree_test - test the click tree
|-- root_command - a root command
+-- root_group - a root group
+-- sub_group - a sub group
|-- default_command (*) - default command of the sub group
+-- other_command - another command of the sub group
"""
)

result = self.runner.invoke(self.click_root, "--tree")
self.assertEqual(result.stdout.rstrip(), expected_stdout)

def test_click_tree_param(self) -> None:
# Ensuring that the get_tree method was called in response to
# the --tree arg is the only thing needed here. Deeper tests are
# handled above.
self.mock_callable(_BASE, "get_tree").to_return_value(
self.expected_tree
).and_assert_called_once()

result = self.runner.invoke(self.click_root, "--tree")
self.assertEqual(result.exit_code, 0)

def test_click_tree_param_not_called(self) -> None:
self.mock_callable(_BASE, "get_tree").to_return_value(
self.expected_tree
).and_assert_called_exactly(0)

result = self.runner.invoke(self.click_root)
self.assertEqual(result.exit_code, 0)

def test_click_tree_param_not_bool(self) -> None:
@click.group("tree_test", short_help="test the click tree")
@click.option(
"--tree",
type=ClickTreeParam(),
help="Enable tree display.",
)
@click.pass_context
def tree_test_click(click_ctx: click.Context, tree: Optional[bool]) -> None:
pass

result = self.runner.invoke(tree_test_click, "--tree=bad")
self.assertEqual(result.exit_code, 1)

0 comments on commit 54be3a7

Please sign in to comment.