From 0c96326f3134fe7fa8384060eb287ddf6b7b1a92 Mon Sep 17 00:00:00 2001 From: Jose Luis Pereira Date: Wed, 4 Dec 2024 11:50:48 +0000 Subject: [PATCH] Feat: Add flag aliases feature --- src/pydantic_argparse/parsers/boolean.py | 2 +- src/pydantic_argparse/parsers/container.py | 2 +- src/pydantic_argparse/parsers/enum.py | 2 +- src/pydantic_argparse/parsers/literal.py | 2 +- src/pydantic_argparse/parsers/mapping.py | 2 +- src/pydantic_argparse/parsers/standard.py | 2 +- src/pydantic_argparse/utils/arguments.py | 12 ++++++++++-- tests/conftest.py | 4 +++- tests/utils/test_arguments.py | 17 ++++++++++------- 9 files changed, 29 insertions(+), 16 deletions(-) diff --git a/src/pydantic_argparse/parsers/boolean.py b/src/pydantic_argparse/parsers/boolean.py index f12e8a1..ca7e0f7 100644 --- a/src/pydantic_argparse/parsers/boolean.py +++ b/src/pydantic_argparse/parsers/boolean.py @@ -53,7 +53,7 @@ def parse_field( # Add Boolean Field parser.add_argument( - utils.arguments.name(field, is_inverted), + *utils.arguments.names(field, is_inverted), action=action, help=utils.arguments.description(field), dest=field.alias, diff --git a/src/pydantic_argparse/parsers/container.py b/src/pydantic_argparse/parsers/container.py index dd304fe..b355e06 100644 --- a/src/pydantic_argparse/parsers/container.py +++ b/src/pydantic_argparse/parsers/container.py @@ -45,7 +45,7 @@ def parse_field( """ # Add Container Field parser.add_argument( - utils.arguments.name(field), + *utils.arguments.names(field), action=argparse._StoreAction, nargs=argparse.ONE_OR_MORE, help=utils.arguments.description(field), diff --git a/src/pydantic_argparse/parsers/enum.py b/src/pydantic_argparse/parsers/enum.py index d643a48..43fd862 100644 --- a/src/pydantic_argparse/parsers/enum.py +++ b/src/pydantic_argparse/parsers/enum.py @@ -54,7 +54,7 @@ def parse_field( # Add Enum Field parser.add_argument( - utils.arguments.name(field, is_inverted), + *utils.arguments.names(field, is_inverted), action=action, help=utils.arguments.description(field), dest=field.alias, diff --git a/src/pydantic_argparse/parsers/literal.py b/src/pydantic_argparse/parsers/literal.py index eab449d..59dcae3 100644 --- a/src/pydantic_argparse/parsers/literal.py +++ b/src/pydantic_argparse/parsers/literal.py @@ -52,7 +52,7 @@ def parse_field( # Add Literal Field parser.add_argument( - utils.arguments.name(field, is_inverted), + *utils.arguments.names(field, is_inverted), action=action, help=utils.arguments.description(field), dest=field.alias, diff --git a/src/pydantic_argparse/parsers/mapping.py b/src/pydantic_argparse/parsers/mapping.py index 77da3e8..87bd74e 100644 --- a/src/pydantic_argparse/parsers/mapping.py +++ b/src/pydantic_argparse/parsers/mapping.py @@ -43,7 +43,7 @@ def parse_field( """ # Add Mapping Field parser.add_argument( - utils.arguments.name(field), + *utils.arguments.names(field), action=argparse._StoreAction, help=utils.arguments.description(field), dest=field.alias, diff --git a/src/pydantic_argparse/parsers/standard.py b/src/pydantic_argparse/parsers/standard.py index e67b555..0471107 100644 --- a/src/pydantic_argparse/parsers/standard.py +++ b/src/pydantic_argparse/parsers/standard.py @@ -29,7 +29,7 @@ def parse_field( """ # Add Standard Field parser.add_argument( - utils.arguments.name(field), + *utils.arguments.names(field), action=argparse._StoreAction, help=utils.arguments.description(field), dest=field.alias, diff --git a/src/pydantic_argparse/utils/arguments.py b/src/pydantic_argparse/utils/arguments.py index 91a083c..ebe9da0 100644 --- a/src/pydantic_argparse/utils/arguments.py +++ b/src/pydantic_argparse/utils/arguments.py @@ -7,7 +7,7 @@ from pydantic_argparse.compatibility import pydantic -def name(field: pydantic.fields.ModelField, invert: bool = False) -> str: +def names(field: pydantic.fields.ModelField, invert: bool = False) -> list[str]: """Standardises argument name. Args: @@ -20,8 +20,16 @@ def name(field: pydantic.fields.ModelField, invert: bool = False) -> str: # Construct Prefix prefix = "--no-" if invert else "--" + flags = [] + + # Add custom aliases + aliases = field.field_info.extra.get("aliases", []) + flags.extend(aliases) + # Prepend prefix, replace '_' with '-' - return f"{prefix}{field.alias.replace('_', '-')}" + flags.append(f"{prefix}{field.alias.replace('_', '-')}") + + return flags def description(field: pydantic.fields.ModelField) -> str: diff --git a/tests/conftest.py b/tests/conftest.py index bbc63b4..fb7d55e 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -48,6 +48,7 @@ def create_test_field( type: Type[Any] = str, # noqa: A002 default: Any = ..., description: Optional[str] = None, + aliases: Optional[list[str]] = None, ) -> pydantic.fields.ModelField: """Constructs a `pydantic` field with sensible defaults for testing. @@ -56,6 +57,7 @@ def create_test_field( type (Type[Any]): Type of the field. default (Any): Default value for the field. description (Optional[str]): Description for the field. + aliases (Optional[list[str]]): List of flag aliases. Returns: pydantic.fields.ModelField: Dynamically constructed `pydantic` model. @@ -63,7 +65,7 @@ def create_test_field( # Construct Pydantic Field return pydantic.fields.ModelField.infer( name=name, - value=pydantic.Field(default, description=description), + value=pydantic.Field(default, description=description, aliases=aliases), annotation=type, class_validators=None, config=pydantic.BaseConfig, diff --git a/tests/utils/test_arguments.py b/tests/utils/test_arguments.py index 75de660..7900cb6 100644 --- a/tests/utils/test_arguments.py +++ b/tests/utils/test_arguments.py @@ -15,18 +15,20 @@ @pytest.mark.parametrize( ( "name", + "aliases", "invert", "expected", ), [ - ("test", False, "--test"), - ("test", True, "--no-test"), - ("test_two", False, "--test-two"), - ("test_two", True, "--no-test-two"), + ("test", ["-t", "-te"], False, ["-t", "-te", "--test"]), + ("test", ["-nt"], True, ["-nt", "--no-test"]), + ("test_two", [], False, ["--test-two"]), + ("test_two", [], True, ["--no-test-two"]), ], ) -def test_argument_name( +def test_argument_names( name: str, + aliases: list[str], invert: bool, expected: str, ) -> None: @@ -34,14 +36,15 @@ def test_argument_name( Args: name (str): Argument name to test. + aliases (list[str]): List of aliases. invert (bool): Whether to invert the name. expected (str): Expected result of the test. """ # Construct Pydantic Field - field = conf.create_test_field(name) + field = conf.create_test_field(name, aliases=aliases) # Generate Argument Name - result = utils.arguments.name(field, invert) + result = utils.arguments.names(field, invert) # Assert assert result == expected