Skip to content

Commit fceab7d

Browse files
authored
Feature: Extra custom aliases (#75)
This is a follow-up PR to #73 which aims to address any bugs, add unit tests and add documentation.
1 parent 977bc47 commit fceab7d

File tree

7 files changed

+62
-45
lines changed

7 files changed

+62
-45
lines changed

README.md

Lines changed: 16 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ import pydantic_argparse
3939

4040
class Arguments(pydantic.BaseModel):
4141
# Required Args
42-
string: str = pydantic.Field(description="a required string")
43-
integer: int = pydantic.Field(description="a required integer")
44-
flag: bool = pydantic.Field(description="a required flag")
42+
string: str = pydantic.Field(description="a required string", aliases=["-s"])
43+
integer: int = pydantic.Field(description="a required integer", aliases=["-i"])
44+
flag: bool = pydantic.Field(description="a required flag", aliases=["-f"])
4545

4646
# Optional Args
4747
second_flag: bool = pydantic.Field(False, description="an optional flag")
@@ -69,29 +69,32 @@ if __name__ == "__main__":
6969

7070
```console
7171
$ python3 example.py --help
72-
usage: Example Program [-h] [-v] --string STRING --integer INTEGER --flag |
73-
--no-flag [--second-flag] [--no-third-flag]
72+
usage: Example Program [-h] [-v] [-s STRING] [-i INTEGER] [-f | --flag | --no-flag]
73+
[--second-flag] [--no-third-flag]
7474

7575
Example Description
7676

7777
required arguments:
78-
--string STRING a required string
79-
--integer INTEGER a required integer
80-
--flag, --no-flag a required flag
78+
-s STRING, --string STRING
79+
a required string
80+
-i INTEGER, --integer INTEGER
81+
a required integer
82+
-f, --flag, --no-flag
83+
a required flag
8184

8285
optional arguments:
83-
--second-flag an optional flag (default: False)
84-
--no-third-flag an optional flag (default: True)
86+
--second-flag an optional flag (default: False)
87+
--no-third-flag an optional flag (default: True)
8588

8689
help:
87-
-h, --help show this help message and exit
88-
-v, --version show program's version number and exit
90+
-h, --help show this help message and exit
91+
-v, --version show program's version number and exit
8992

9093
Example Epilog
9194
```
9295

9396
```console
94-
$ python3 example.py --string hello --integer 42 --flag
97+
$ python3 example.py --string hello -i 42 -f
9598
string='hello' integer=42 flag=True second_flag=False third_flag=True
9699
```
97100

docs/examples/simple.md

Lines changed: 13 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6,29 +6,32 @@
66
### Check Help
77
```console
88
$ python3 simple.py --help
9-
usage: Example Program [-h] [-v] --string STRING --integer INTEGER --flag |
10-
--no-flag [--second-flag] [--no-third-flag]
9+
usage: Example Program [-h] [-v] [-s STRING] [-i INTEGER] [-f | --flag | --no-flag]
10+
[--second-flag] [--no-third-flag]
1111

1212
Example Description
1313

1414
required arguments:
15-
--string STRING a required string
16-
--integer INTEGER a required integer
17-
--flag, --no-flag a required flag
15+
-s STRING, --string STRING
16+
a required string
17+
-i INTEGER, --integer INTEGER
18+
a required integer
19+
-f, --flag, --no-flag
20+
a required flag
1821

1922
optional arguments:
20-
--second-flag an optional flag (default: False)
21-
--no-third-flag an optional flag (default: True)
23+
--second-flag an optional flag (default: False)
24+
--no-third-flag an optional flag (default: True)
2225

2326
help:
24-
-h, --help show this help message and exit
25-
-v, --version show program's version number and exit
27+
-h, --help show this help message and exit
28+
-v, --version show program's version number and exit
2629

2730
Example Epilog
2831
```
2932

3033
### Parse Arguments
3134
```console
32-
$ python3 simple.py --string hello --integer 42 --flag
35+
$ python3 simple.py --string hello -i 42 -f
3336
string='hello' integer=42 flag=True second_flag=False third_flag=True
3437
```

docs/usage/arguments/index.md

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,18 @@ class Arguments(BaseModel):
111111
You can see the list of reserved keywords in Python at any time by typing
112112
`:::python help("keywords")` into the Python interpreter.
113113

114+
A field can also be provided with a list of `aliases`, which will allow the
115+
argument to be provided via multiple different (potentially shorter) aliases in
116+
the command-line interface.
117+
118+
```python
119+
class Arguments(BaseModel):
120+
# We want our argument to be named `my_long_argument_name` (i.e.,
121+
# `--my-long-argument-name`), but we also want to provide the argument via
122+
# the aliases `-m` and `-mlan`.
123+
my_long_argument_name: int = Field(aliases=["-m", "-mlan"])
124+
```
125+
114126
## Environment Variables
115127
Functionality to parse both required and optional arguments from environment
116128
variables is provided via the `pydantic.BaseSettings` base class.

examples/simple.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,9 +9,9 @@ class Arguments(pydantic.BaseModel):
99
"""Simple Command-Line Arguments."""
1010

1111
# Required Args
12-
string: str = pydantic.Field(description="a required string")
13-
integer: int = pydantic.Field(description="a required integer")
14-
flag: bool = pydantic.Field(description="a required flag")
12+
string: str = pydantic.Field(description="a required string", aliases=["-s"])
13+
integer: int = pydantic.Field(description="a required integer", aliases=["-i"])
14+
flag: bool = pydantic.Field(description="a required flag", aliases=["-f"])
1515

1616
# Optional Args
1717
second_flag: bool = pydantic.Field(False, description="an optional flag")

src/pydantic_argparse/utils/arguments.py

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -6,30 +6,29 @@
66

77
from pydantic_argparse.compatibility import pydantic
88

9+
from typing import List
910

10-
def names(field: pydantic.fields.ModelField, invert: bool = False) -> list[str]:
11-
"""Standardises argument name.
11+
12+
def names(field: pydantic.fields.ModelField, invert: bool = False) -> List[str]:
13+
"""Standardises the argument name and any custom aliases.
1214
1315
Args:
1416
field (pydantic.fields.ModelField): Field to construct name for.
1517
invert (bool): Whether to invert the name by prepending `--no-`.
1618
1719
Returns:
18-
str: Standardised name of the argument.
20+
List[str]: Standardised names for the argument.
1921
"""
20-
# Construct Prefix
21-
prefix = "--no-" if invert else "--"
22-
23-
flags = []
22+
# Add any custom aliases first
23+
# We trust that the user has provided these correctly
24+
flags: List[str] = []
25+
flags.extend(field.field_info.extra.get("aliases", []))
2426

25-
# Add custom aliases
26-
aliases = field.field_info.extra.get("aliases", [])
27-
for alias in aliases:
28-
flags.append(f"{prefix}{alias.replace('_', '-')}")
29-
30-
# Prepend prefix, replace '_' with '-'
27+
# Construct prefix, prepend it, replace '_' with '-'
28+
prefix = "--no-" if invert else "--"
3129
flags.append(f"{prefix}{field.alias.replace('_', '-')}")
3230

31+
# Return the standardised name and aliases
3332
return flags
3433

3534

tests/conftest.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ def create_test_field(
4848
type: Type[Any] = str, # noqa: A002
4949
default: Any = ...,
5050
description: Optional[str] = None,
51-
aliases: Optional[list[str]] = None,
51+
aliases: Optional[List[str]] = None,
5252
) -> pydantic.fields.ModelField:
5353
"""Constructs a `pydantic` field with sensible defaults for testing.
5454
@@ -57,7 +57,7 @@ def create_test_field(
5757
type (Type[Any]): Type of the field.
5858
default (Any): Default value for the field.
5959
description (Optional[str]): Description for the field.
60-
aliases (Optional[list[str]]): List of flag aliases.
60+
aliases (Optional[List[str]]): List of flag aliases.
6161
6262
Returns:
6363
pydantic.fields.ModelField: Dynamically constructed `pydantic` model.

tests/utils/test_arguments.py

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@
99
from pydantic_argparse import utils
1010
from tests import conftest as conf
1111

12-
from typing import Any, Optional
12+
from typing import Any, List, Optional
1313

1414

1515
@pytest.mark.parametrize(
@@ -28,15 +28,15 @@
2828
)
2929
def test_argument_names(
3030
name: str,
31-
aliases: list[str],
31+
aliases: List[str],
3232
invert: bool,
3333
expected: str,
3434
) -> None:
35-
"""Tests `utils.arguments.name` Function.
35+
"""Tests `utils.arguments.names` Function.
3636
3737
Args:
3838
name (str): Argument name to test.
39-
aliases (list[str]): List of aliases.
39+
aliases (List[str]): List of aliases.
4040
invert (bool): Whether to invert the name.
4141
expected (str): Expected result of the test.
4242
"""

0 commit comments

Comments
 (0)