bonus-click 0.0.1__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- bonus_click-0.0.1/AUTHORS.md +7 -0
- bonus_click-0.0.1/LICENSE.md +21 -0
- bonus_click-0.0.1/PKG-INFO +119 -0
- bonus_click-0.0.1/README.md +101 -0
- bonus_click-0.0.1/bonus_click/__init__.py +6 -0
- bonus_click-0.0.1/bonus_click/_options/__init__.py +0 -0
- bonus_click-0.0.1/bonus_click/_options/enum_option.py +85 -0
- bonus_click-0.0.1/bonus_click/options.py +9 -0
- bonus_click-0.0.1/bonus_click/py.typed +0 -0
- bonus_click-0.0.1/pyproject.toml +68 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Devon Bray
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in
|
|
13
|
+
all copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
21
|
+
THE SOFTWARE.
|
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: bonus_click
|
|
3
|
+
Version: 0.0.1
|
|
4
|
+
Summary: Convenience wrappers around helpful click patterns.
|
|
5
|
+
License-File: AUTHORS.md
|
|
6
|
+
License-File: LICENSE.md
|
|
7
|
+
Author: Devon Bray
|
|
8
|
+
Requires-Python: >=3.10,<4.0
|
|
9
|
+
Classifier: Programming Language :: Python :: 3
|
|
10
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
11
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
12
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
13
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
14
|
+
Classifier: Programming Language :: Python :: 3.14
|
|
15
|
+
Requires-Dist: click (>=8.3.0,<9.0.0)
|
|
16
|
+
Description-Content-Type: text/markdown
|
|
17
|
+
|
|
18
|
+
# Bonus Click - `bonus_click`
|
|
19
|
+
|
|
20
|
+

|
|
21
|
+
|
|
22
|
+
Convenience wrappers around helpful [click](https://click.palletsprojects.com/en/stable/) patterns.
|
|
23
|
+
|
|
24
|
+
## Getting Started
|
|
25
|
+
|
|
26
|
+
### Python Dependencies
|
|
27
|
+
|
|
28
|
+
Poetry is required to manage Python dependencies. You can install it easily by following the
|
|
29
|
+
operating system specific instructions [here](https://python-poetry.org/docs/#installation).
|
|
30
|
+
|
|
31
|
+
`pyproject.toml` contains dependencies for required Python modules for building, testing, and
|
|
32
|
+
developing. They can all be installed in a [virtual environment](https://docs.python.org/3/library/venv.html)
|
|
33
|
+
using the follow commands:
|
|
34
|
+
|
|
35
|
+
```
|
|
36
|
+
python3.10 -m venv .venv
|
|
37
|
+
source ./.venv/bin/activate
|
|
38
|
+
poetry install
|
|
39
|
+
```
|
|
40
|
+
|
|
41
|
+
There's also a bin script to do this, and will install poetry if you don't already have it:
|
|
42
|
+
|
|
43
|
+
```
|
|
44
|
+
./tools/create_venv.sh
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
## Developer Guide
|
|
48
|
+
|
|
49
|
+
The following is documentation for developers that would like to contribute
|
|
50
|
+
to Bonus Click.
|
|
51
|
+
|
|
52
|
+
### Testing
|
|
53
|
+
|
|
54
|
+
This project uses pytest to manage and run unit tests. Unit tests located in the `test` directory
|
|
55
|
+
are automatically run during the CI build. You can run them manually with:
|
|
56
|
+
|
|
57
|
+
```
|
|
58
|
+
./tools/run_tests.sh
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
### Local Linting
|
|
62
|
+
|
|
63
|
+
There are a few linters/code checks included with this project to speed up the development process:
|
|
64
|
+
|
|
65
|
+
* Black - An automatic code formatter, never think about python style again.
|
|
66
|
+
* Isort - Automatically organizes imports in your modules.
|
|
67
|
+
* Pylint - Check your code against many of the python style guide rules.
|
|
68
|
+
* Mypy - Check your code to make sure it is properly typed.
|
|
69
|
+
|
|
70
|
+
You can run these tools automatically in check mode, meaning you will get an error if any of them
|
|
71
|
+
would not pass with:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
./tools/run_checks.sh
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
Or actually automatically apply the fixes with:
|
|
78
|
+
|
|
79
|
+
```
|
|
80
|
+
./tools/apply_linters.sh
|
|
81
|
+
```
|
|
82
|
+
|
|
83
|
+
There are also scripts in `./tools/` that include run/check for each individual tool.
|
|
84
|
+
|
|
85
|
+
|
|
86
|
+
### Using pre-commit
|
|
87
|
+
|
|
88
|
+
Upon cloning the repo, to use pre-commit, you'll need to install the hooks with:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
pre-commit install --hook-type pre-commit --hook-type pre-push
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
By default:
|
|
95
|
+
|
|
96
|
+
* black
|
|
97
|
+
* pylint
|
|
98
|
+
* isort
|
|
99
|
+
* mypy
|
|
100
|
+
|
|
101
|
+
Are all run in apply-mode and must pass in order to actually make the commit.
|
|
102
|
+
|
|
103
|
+
Also by default, pytest needs to pass before you can push.
|
|
104
|
+
|
|
105
|
+
If you'd like skip these checks you can commit with:
|
|
106
|
+
|
|
107
|
+
```
|
|
108
|
+
git commit --no-verify
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
If you'd like to quickly run these pre-commit checks on all files (not just the staged ones) you
|
|
112
|
+
can run:
|
|
113
|
+
|
|
114
|
+
```
|
|
115
|
+
pre-commit run --all-files
|
|
116
|
+
```
|
|
117
|
+
|
|
118
|
+
|
|
119
|
+
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
# Bonus Click - `bonus_click`
|
|
2
|
+
|
|
3
|
+

|
|
4
|
+
|
|
5
|
+
Convenience wrappers around helpful [click](https://click.palletsprojects.com/en/stable/) patterns.
|
|
6
|
+
|
|
7
|
+
## Getting Started
|
|
8
|
+
|
|
9
|
+
### Python Dependencies
|
|
10
|
+
|
|
11
|
+
Poetry is required to manage Python dependencies. You can install it easily by following the
|
|
12
|
+
operating system specific instructions [here](https://python-poetry.org/docs/#installation).
|
|
13
|
+
|
|
14
|
+
`pyproject.toml` contains dependencies for required Python modules for building, testing, and
|
|
15
|
+
developing. They can all be installed in a [virtual environment](https://docs.python.org/3/library/venv.html)
|
|
16
|
+
using the follow commands:
|
|
17
|
+
|
|
18
|
+
```
|
|
19
|
+
python3.10 -m venv .venv
|
|
20
|
+
source ./.venv/bin/activate
|
|
21
|
+
poetry install
|
|
22
|
+
```
|
|
23
|
+
|
|
24
|
+
There's also a bin script to do this, and will install poetry if you don't already have it:
|
|
25
|
+
|
|
26
|
+
```
|
|
27
|
+
./tools/create_venv.sh
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Developer Guide
|
|
31
|
+
|
|
32
|
+
The following is documentation for developers that would like to contribute
|
|
33
|
+
to Bonus Click.
|
|
34
|
+
|
|
35
|
+
### Testing
|
|
36
|
+
|
|
37
|
+
This project uses pytest to manage and run unit tests. Unit tests located in the `test` directory
|
|
38
|
+
are automatically run during the CI build. You can run them manually with:
|
|
39
|
+
|
|
40
|
+
```
|
|
41
|
+
./tools/run_tests.sh
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Local Linting
|
|
45
|
+
|
|
46
|
+
There are a few linters/code checks included with this project to speed up the development process:
|
|
47
|
+
|
|
48
|
+
* Black - An automatic code formatter, never think about python style again.
|
|
49
|
+
* Isort - Automatically organizes imports in your modules.
|
|
50
|
+
* Pylint - Check your code against many of the python style guide rules.
|
|
51
|
+
* Mypy - Check your code to make sure it is properly typed.
|
|
52
|
+
|
|
53
|
+
You can run these tools automatically in check mode, meaning you will get an error if any of them
|
|
54
|
+
would not pass with:
|
|
55
|
+
|
|
56
|
+
```
|
|
57
|
+
./tools/run_checks.sh
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
Or actually automatically apply the fixes with:
|
|
61
|
+
|
|
62
|
+
```
|
|
63
|
+
./tools/apply_linters.sh
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
There are also scripts in `./tools/` that include run/check for each individual tool.
|
|
67
|
+
|
|
68
|
+
|
|
69
|
+
### Using pre-commit
|
|
70
|
+
|
|
71
|
+
Upon cloning the repo, to use pre-commit, you'll need to install the hooks with:
|
|
72
|
+
|
|
73
|
+
```
|
|
74
|
+
pre-commit install --hook-type pre-commit --hook-type pre-push
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
By default:
|
|
78
|
+
|
|
79
|
+
* black
|
|
80
|
+
* pylint
|
|
81
|
+
* isort
|
|
82
|
+
* mypy
|
|
83
|
+
|
|
84
|
+
Are all run in apply-mode and must pass in order to actually make the commit.
|
|
85
|
+
|
|
86
|
+
Also by default, pytest needs to pass before you can push.
|
|
87
|
+
|
|
88
|
+
If you'd like skip these checks you can commit with:
|
|
89
|
+
|
|
90
|
+
```
|
|
91
|
+
git commit --no-verify
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
If you'd like to quickly run these pre-commit checks on all files (not just the staged ones) you
|
|
95
|
+
can run:
|
|
96
|
+
|
|
97
|
+
```
|
|
98
|
+
pre-commit run --all-files
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
|
|
File without changes
|
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
"""
|
|
2
|
+
Uses enums to define different choices the user can make in your CLI.
|
|
3
|
+
"""
|
|
4
|
+
|
|
5
|
+
from enum import Enum
|
|
6
|
+
from typing import Callable, Optional, TypeVar
|
|
7
|
+
|
|
8
|
+
import click
|
|
9
|
+
from click import Context, Parameter
|
|
10
|
+
from click.decorators import FC
|
|
11
|
+
|
|
12
|
+
# A generic type variable for Enum subclasses, essentially any enum subclass.
|
|
13
|
+
E = TypeVar("E", bound=Enum)
|
|
14
|
+
T = TypeVar("T")
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
def create_enum_option( # pylint: disable=too-many-positional-arguments
|
|
18
|
+
arg_flag: str,
|
|
19
|
+
help_message: str,
|
|
20
|
+
default: E,
|
|
21
|
+
input_enum: type[E],
|
|
22
|
+
lookup_fn: Optional[Callable[[E], T]] = None,
|
|
23
|
+
envvar: Optional[str] = None,
|
|
24
|
+
) -> Callable[[FC], FC]:
|
|
25
|
+
"""
|
|
26
|
+
Creates a Click option for an Enum type. Resulting input can be given as an index or as the
|
|
27
|
+
string value from the enum.
|
|
28
|
+
|
|
29
|
+
:param arg_flag: The argument flag for the Click option (e.g., "--output").
|
|
30
|
+
:param help_message: Will be included in the --help message alongside the acceptable inputs
|
|
31
|
+
to the Enum.
|
|
32
|
+
:param default: The default value for the Click option, must be a member of `input_enum`.
|
|
33
|
+
:param lookup_fn: If given, the resolved value will be passed to this function, then the click
|
|
34
|
+
command will get whatever is returned as an argument.
|
|
35
|
+
:param input_enum: The Enum class from which the option values are derived.
|
|
36
|
+
:param envvar: Passed to the click option.
|
|
37
|
+
:return: A Click option configured for the specified Enum.
|
|
38
|
+
"""
|
|
39
|
+
|
|
40
|
+
try:
|
|
41
|
+
input_enum(default)
|
|
42
|
+
except ValueError as e:
|
|
43
|
+
raise ValueError("Default value was not a member of the enum!") from e
|
|
44
|
+
|
|
45
|
+
options_string = "\n".join(
|
|
46
|
+
[f" {idx}: {enum_member.value}" for idx, enum_member in enumerate(input_enum)]
|
|
47
|
+
)
|
|
48
|
+
|
|
49
|
+
help_string = (
|
|
50
|
+
f"\b\n{help_message}\nOptions below. Either provide index or value:\n{options_string}"
|
|
51
|
+
)
|
|
52
|
+
|
|
53
|
+
def callback(_ctx: Context, _param: Parameter, value: str) -> "T | E":
|
|
54
|
+
enum_options = list(input_enum)
|
|
55
|
+
try:
|
|
56
|
+
# Try interpreting as an index
|
|
57
|
+
index = int(value)
|
|
58
|
+
if 0 <= index < len(enum_options):
|
|
59
|
+
return enum_options[index]
|
|
60
|
+
else:
|
|
61
|
+
raise click.BadParameter(
|
|
62
|
+
f"Index out of range. Valid range: 0-{len(enum_options)-1}."
|
|
63
|
+
)
|
|
64
|
+
except ValueError:
|
|
65
|
+
# If not an index, validate as a string
|
|
66
|
+
try:
|
|
67
|
+
resolved: E = input_enum(value)
|
|
68
|
+
return lookup_fn(resolved) if lookup_fn else resolved
|
|
69
|
+
except ValueError as e:
|
|
70
|
+
valid_choices = ", ".join([e.value for e in enum_options])
|
|
71
|
+
raise click.BadParameter(
|
|
72
|
+
"Invalid choice. "
|
|
73
|
+
f"Valid names: {valid_choices}, or indices 0-{len(enum_options)-1}."
|
|
74
|
+
) from e
|
|
75
|
+
|
|
76
|
+
return click.option(
|
|
77
|
+
arg_flag,
|
|
78
|
+
type=click.STRING,
|
|
79
|
+
callback=callback,
|
|
80
|
+
help=help_string,
|
|
81
|
+
default=default.value, # Ensure we use the string value for the default
|
|
82
|
+
show_default=True,
|
|
83
|
+
envvar=envvar,
|
|
84
|
+
show_envvar=True,
|
|
85
|
+
)
|
|
File without changes
|
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
build-backend = "poetry.core.masonry.api"
|
|
3
|
+
requires = ["poetry-core"]
|
|
4
|
+
|
|
5
|
+
[tool.black]
|
|
6
|
+
line-length = 100
|
|
7
|
+
target-version = ['py310']
|
|
8
|
+
|
|
9
|
+
[tool.isort]
|
|
10
|
+
extra_standard_library = "setuptools,typing_extensions"
|
|
11
|
+
force_grid_wrap = 0
|
|
12
|
+
include_trailing_comma = true
|
|
13
|
+
line_length = 100
|
|
14
|
+
multi_line_output = 3
|
|
15
|
+
skip = ["/home/circleci/repo/venv", "./venv", "./.venv"]
|
|
16
|
+
use_parentheses = true
|
|
17
|
+
|
|
18
|
+
[tool.mypy]
|
|
19
|
+
allow_redefinition = false
|
|
20
|
+
check_untyped_defs = true
|
|
21
|
+
disallow_any_explicit = true
|
|
22
|
+
disallow_any_generics = true
|
|
23
|
+
disallow_incomplete_defs = true
|
|
24
|
+
disallow_subclassing_any = true
|
|
25
|
+
disallow_untyped_calls = true
|
|
26
|
+
disallow_untyped_defs = true
|
|
27
|
+
ignore_missing_imports = true
|
|
28
|
+
mypy_path = ".:test:bonus_click"
|
|
29
|
+
no_implicit_optional = true
|
|
30
|
+
scripts_are_modules = true
|
|
31
|
+
strict_optional = false
|
|
32
|
+
warn_incomplete_stub = true
|
|
33
|
+
warn_redundant_casts = true
|
|
34
|
+
warn_return_any = true
|
|
35
|
+
warn_unused_ignores = true
|
|
36
|
+
|
|
37
|
+
[tool.poetry]
|
|
38
|
+
authors = ["Devon Bray"]
|
|
39
|
+
description = "Convenience wrappers around helpful click patterns."
|
|
40
|
+
name = "bonus_click"
|
|
41
|
+
readme = "README.md"
|
|
42
|
+
version = "0.0.1"
|
|
43
|
+
|
|
44
|
+
[tool.poetry.dependencies]
|
|
45
|
+
python = "^3.10"
|
|
46
|
+
click = "^8.3.0"
|
|
47
|
+
|
|
48
|
+
[tool.poetry.group.dev.dependencies]
|
|
49
|
+
black = "*"
|
|
50
|
+
isort = "*"
|
|
51
|
+
mypy = "*"
|
|
52
|
+
pre-commit = "*"
|
|
53
|
+
pylint = "*"
|
|
54
|
+
pydevd-pycharm = ">=231.8109.197,<231.8110.0"
|
|
55
|
+
wheel = "^0.38"
|
|
56
|
+
|
|
57
|
+
[tool.poetry.group.test.dependencies]
|
|
58
|
+
coverage = "*"
|
|
59
|
+
pytest = "*"
|
|
60
|
+
pytest-cov = "*"
|
|
61
|
+
|
|
62
|
+
[tool.pytest.ini_options]
|
|
63
|
+
addopts = "-rsxX --showlocals --strict-markers"
|
|
64
|
+
|
|
65
|
+
[tool.pytest.ini_options.markers]
|
|
66
|
+
devtest = "temporary development mark that can be used as needed (should not be merged to master)"
|
|
67
|
+
integration = "tests that access outside services (s3, APIs), don't run in CircleCI"
|
|
68
|
+
timeout = "timeout for test in seconds, from `pytest-timeout` module"
|