Skip to content

Commit b254ab8

Browse files
committed
feat: Added -h flag for the --help menu unless overridden
1 parent a80b7c4 commit b254ab8

File tree

8 files changed

+580
-15
lines changed

8 files changed

+580
-15
lines changed

.gitignore

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# Other
22
.DS_Store
3-
/test.py
3+
/test*.py
44

55
# Byte-compiled / optimized / DLL files
66
__pycache__/

README.md

Lines changed: 17 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12,17 +12,28 @@
1212

1313
A powerful extension for [Click](https://click.palletsprojects.com/) that adds **command and group aliasing** support with **automatic async function handling** and **advanced parameter validation**.
1414

15+
You can find the project on [PyPi](https://pypi.org/project/click-with-aliasing/).
16+
1517
## Features
1618

1719
- **Command Aliases**: Create multiple names for your commands
1820
- **Group Aliases**: Add aliases to command groups
21+
- **Help Alias (-h)**: Automatic `-h` shorthand for `--help` with conflict detection
1922
- **Enhanced Options & Arguments**: Mutual exclusivity, requirements, and group constraints
2023
- **Validation Rules**: Group-level validation with multiple modes (all_or_none, at_least, at_most, exactly)
2124
- **Automatic Async Support**: Seamlessly handle async functions without extra configuration
2225
- **Drop-in Replacement**: Works exactly like standard Click decorators
2326
- **Type Safe**: Full type hints support with proper IDE integration
2427
- **Help Integration**: Aliases automatically appear in help text
2528

29+
## Installation
30+
31+
```bash
32+
pip install click-with-aliasing
33+
```
34+
35+
**Requirements:** Python 3.10 or newer
36+
2637
## Documentation
2738

2839
- **[Command](docs/COMMAND.md)** - Command decorator with aliasing support
@@ -31,13 +42,7 @@ A powerful extension for [Click](https://click.palletsprojects.com/) that adds *
3142
- **[Argument](docs/ARGUMENT.md)** - Enhanced arguments with validation constraints
3243
- **[Rule](docs/RULE.md)** - Group-level validation rules for complex parameter logic
3344

34-
## Installation
35-
36-
```bash
37-
pip install click-with-aliasing
38-
```
39-
40-
**Requirements:** Python 3.10 or newer
45+
> **Note:** Both `-h` and `--help` flags are supported by default. See the [Command](docs/COMMAND.md) and [Group](docs/GROUP.md) documentation for details on how `-h` is intelligently handled when commands use it for other purposes.
4146
4247
## Quick Start
4348

@@ -134,7 +139,7 @@ Usage:
134139
my-cli deploy --production # Valid
135140
my-cli deploy --staging # Valid
136141
my-cli deploy --production --staging # Error: exactly 1 required
137-
my-cli deploy # Error: exactly 1 required
142+
my-cli deploy # Error: exactly 1 required
138143
```
139144

140145
## Async Support
@@ -260,7 +265,7 @@ All standard Click features work exactly the same, with optional enhancements av
260265

261266
## Help Text Integration
262267

263-
Aliases automatically appear in help text:
268+
Aliases automatically appear in help text, and both `-h` and `--help` work for displaying help:
264269

265270
```txt
266271
myapp database --help
@@ -269,13 +274,15 @@ Usage: myapp database [OPTIONS] COMMAND [ARGS]...
269274
Database management commands
270275
271276
Options:
272-
--help Show this message and exit.
277+
-h, --help Show this message and exit.
273278
274279
Commands:
275280
migrate (m, mig) Run database migrations
276281
seed (s) Seed the database
277282
```
278283

284+
The `-h` flag is automatically added unless a command uses it for another purpose (like `--host`), ensuring consistent help access while avoiding conflicts.
285+
279286
## Contributing
280287

281288
Contributions are welcome! Please read our [Contributing Guide](CONTRIBUTING.md) for details on our development process, coding standards, and how to submit pull requests.

click_with_aliasing/command.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,64 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
2323
self.aliases: list[str] = kwargs.pop("aliases", [])
2424
super().__init__(*args, **kwargs)
2525

26+
def get_help_option(self, ctx: click.Context) -> click.Option | None:
27+
"""
28+
Get the help option with -h alias support.
29+
30+
This method adds -h as an alias for --help unless the command
31+
uses -h for another purpose.
32+
33+
Args:
34+
ctx (click.Context):
35+
The Click context.
36+
37+
Returns:
38+
click.Option | None:
39+
The help option with -h alias, or None if help is disabled.
40+
"""
41+
help_option_names = self.get_help_option_names(ctx)
42+
if not help_option_names:
43+
return None
44+
45+
# Check if this command uses -h for another purpose
46+
has_h_conflict = False
47+
for param in self.params:
48+
if hasattr(param, "opts") and "-h" in param.opts:
49+
has_h_conflict = True
50+
break
51+
52+
# Add -h to help option names if no conflict
53+
if not has_h_conflict and "-h" not in help_option_names:
54+
help_option_names = ["-h"] + list(help_option_names)
55+
56+
return click.Option(
57+
help_option_names,
58+
is_flag=True,
59+
is_eager=True,
60+
expose_value=False,
61+
callback=self._show_help_callback,
62+
help="Show this message and exit.",
63+
)
64+
65+
@staticmethod
66+
def _show_help_callback(
67+
ctx: click.Context, param: click.Parameter, value: bool
68+
) -> None:
69+
"""
70+
Callback to show help message.
71+
72+
Args:
73+
ctx (click.Context):
74+
The Click context.
75+
param (click.Parameter):
76+
The parameter that triggered the callback.
77+
value (bool):
78+
The value of the parameter.
79+
"""
80+
if value and not ctx.resilient_parsing:
81+
click.echo(ctx.get_help(), color=ctx.color)
82+
ctx.exit()
83+
2684

2785
def command(
2886
name: str,

click_with_aliasing/group.py

Lines changed: 66 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,72 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
2323
self.aliases: list[str] = kwargs.pop("aliases", [])
2424
super().__init__(*args, **kwargs)
2525

26+
def get_help_option(self, ctx: click.Context) -> click.Option | None:
27+
"""
28+
Get the help option with -h alias support.
29+
30+
This method adds -h as an alias for --help unless the group itself or
31+
any command in the group uses -h for another purpose.
32+
33+
Args:
34+
ctx (click.Context):
35+
The Click context.
36+
37+
Returns:
38+
click.Option | None:
39+
The help option with -h alias, or None if help is disabled.
40+
"""
41+
help_option_names = self.get_help_option_names(ctx)
42+
if not help_option_names:
43+
return None
44+
45+
has_h_conflict = False
46+
for param in self.params:
47+
if hasattr(param, "opts") and "-h" in param.opts:
48+
has_h_conflict = True
49+
break
50+
51+
if not has_h_conflict:
52+
for cmd_name, cmd in self.commands.items():
53+
if cmd_name == cmd.name:
54+
for param in getattr(cmd, "params", []):
55+
if hasattr(param, "opts") and "-h" in param.opts:
56+
has_h_conflict = True
57+
break
58+
if has_h_conflict:
59+
break
60+
61+
if not has_h_conflict and "-h" not in help_option_names:
62+
help_option_names = ["-h"] + list(help_option_names)
63+
64+
return click.Option(
65+
help_option_names,
66+
is_flag=True,
67+
is_eager=True,
68+
expose_value=False,
69+
callback=self._show_help_callback,
70+
help="Show this message and exit.",
71+
)
72+
73+
@staticmethod
74+
def _show_help_callback(
75+
ctx: click.Context, param: click.Parameter, value: bool
76+
) -> None:
77+
"""
78+
Callback to show help message.
79+
80+
Args:
81+
ctx (click.Context):
82+
The Click context.
83+
param (click.Parameter):
84+
The parameter that triggered the callback.
85+
value (bool):
86+
The value of the parameter.
87+
"""
88+
if value and not ctx.resilient_parsing:
89+
click.echo(ctx.get_help(), color=ctx.color)
90+
ctx.exit()
91+
2692
def add_command(self, cmd: click.Command, name: str | None = None) -> None:
2793
"""
2894
Add a command to the group, including its aliases.

docs/COMMAND.md

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -34,9 +34,9 @@ def deploy():
3434
All of these work:
3535

3636
```bash
37-
$ python app.py deploy
38-
$ python app.py d
39-
$ python app.py dep
37+
python app.py deploy
38+
python app.py d
39+
python app.py dep
4040
```
4141

4242
## With Parameters
@@ -179,6 +179,57 @@ Commands:
179179
deploy (d, dep) Deploy the application to production
180180
```
181181

182+
### Help Flag (-h)
183+
184+
By default, commands support both `-h` and `--help` for displaying help:
185+
186+
```python
187+
from click_with_aliasing import command
188+
189+
@command("process")
190+
def process():
191+
"""Process data"""
192+
print("Processing...")
193+
```
194+
195+
```bash
196+
$ python app.py process -h
197+
Usage: app.py process [OPTIONS]
198+
199+
Process data
200+
201+
Options:
202+
-h, --help Show this message and exit.
203+
```
204+
205+
However, if a command uses `-h` for another option, it will not have `-h` as a help alias:
206+
207+
```python
208+
from click_with_aliasing import command, option
209+
210+
@command("connect")
211+
@option("--host", "-h", help="Server hostname")
212+
def connect(host):
213+
"""Connect to a server"""
214+
print(f"Connecting to {host}")
215+
```
216+
217+
```bash
218+
# -h is used for --host option
219+
$ python app.py connect -h localhost
220+
Connecting to localhost
221+
222+
# Help is available via --help only
223+
$ python app.py connect --help
224+
Usage: app.py connect [OPTIONS]
225+
226+
Connect to a server
227+
228+
Options:
229+
-h, --host TEXT Server hostname
230+
--help Show this message and exit.
231+
```
232+
182233
## API Reference
183234

184235
```python

docs/GROUP.md

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -273,6 +273,63 @@ Commands:
273273
seed (s) Seed the database
274274
```
275275

276+
### Help Flag (-h)
277+
278+
By default, groups support both `-h` and `--help` for displaying help:
279+
280+
```python
281+
from click_with_aliasing import group
282+
283+
@group()
284+
def cli():
285+
"""My CLI application"""
286+
pass
287+
```
288+
289+
```bash
290+
$ python app.py -h
291+
Usage: app.py [OPTIONS] COMMAND [ARGS]...
292+
293+
My CLI application
294+
295+
Options:
296+
-h, --help Show this message and exit.
297+
```
298+
299+
However, if any command in the group uses `-h` for another purpose, the group will only show `--help`:
300+
301+
```python
302+
from click_with_aliasing import group, command, option
303+
304+
@group()
305+
def cli():
306+
"""Network tools"""
307+
pass
308+
309+
@command("ping")
310+
@option("--host", "-h", required=True, help="Target host")
311+
def ping(host):
312+
"""Ping a host"""
313+
print(f"Pinging {host}")
314+
315+
cli.add_command(ping)
316+
```
317+
318+
```bash
319+
# Group only has --help (not -h) because ping command uses -h
320+
$ python app.py --help
321+
Usage: app.py [OPTIONS] COMMAND [ARGS]...
322+
323+
Network tools
324+
325+
Options:
326+
--help Show this message and exit.
327+
328+
# The ping command uses -h for --host
329+
$ python app.py ping -h localhost
330+
Pinging localhost
331+
```
332+
276333
## API Reference
277334

278335
```python

pyproject.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[project]
22
name = "click_with_aliasing"
3-
version = "1.2.0"
3+
version = "1.2.1"
44
description = "A library that allows you to add aliases to your Click group and commands."
55
authors = [
66
{ name = "Marcus Fredriksson", email = "marcus@marcusfredriksson.com" },

0 commit comments

Comments
 (0)