-
Notifications
You must be signed in to change notification settings - Fork 18
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
* First method of recursive subcommand parsing. * Fixed non-recursive mistake. * Renamed `parent_command` to `command`. * Renamed `commands` to `subcommands` * Fixed malformed docstring arg. * Fixed future imports in unit tests * Unified handling of combining command strings for namespacing. * Fixed mangled metavars. * Fixed pylint no-self-use. * Added check for dest in kwargs before augmenting. * Remove 'parent command' method. * Updated dependencies. * Added custom SubParserAction to easily parse commands. * Rearranged functions * Improved SubParsersAction docstring. * Added full propagation of unrecognized args to top level namespace. * Guarded unrecognized args propagation with check. * Refactored __version__ and unit test structure. * Restructured unit tests again. * Linting and styleguide changes. * Updated pyproject.toml * Bumped back to 0.3.1 after merge. * Added unit tests for 'utils' module. * Completed full unit test coverage of commands.
- Loading branch information
Showing
25 changed files
with
924 additions
and
532 deletions.
There are no files selected for viewing
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,7 +5,6 @@ | |
@author Hayden Richards <[email protected]> | ||
""" | ||
|
||
|
||
# Local | ||
from .__version__ import __app__, __description__, __version__, __authors__ | ||
from .__version__ import __title__, __description__, __version__, __author__, __license__ | ||
from .argparse import ArgumentParser |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,13 +1,18 @@ | ||
"""__version__.py | ||
Exports the name, version, description and authors of the package | ||
Exports the title, description, version, author and license of the package | ||
@author Hayden Richards <[email protected]> | ||
""" | ||
|
||
|
||
# Duplicated from `pyproject.toml` | ||
__app__ = "pydantic-argparse" | ||
__description__ = "Typed Argument Parsing with Pydantic" | ||
__version__ = "0.3.1" | ||
__authors__ = ["Hayden Richards <[email protected]>"] | ||
# Standard | ||
from importlib import metadata | ||
|
||
|
||
# Retrieve Metadata from Package | ||
__title__ = metadata.metadata(__package__)["name"] | ||
__description__ = metadata.metadata(__package__)["summary"] | ||
__version__ = metadata.metadata(__package__)["version"] | ||
__author__ = metadata.metadata(__package__)["author"] | ||
__license__ = metadata.metadata(__package__)["license"] |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,6 +5,5 @@ | |
@author Hayden Richards <[email protected]> | ||
""" | ||
|
||
|
||
# Local | ||
from .parser import ArgumentParser |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,105 @@ | ||
"""actions.py | ||
Provides custom Actions classes. | ||
@author Hayden Richards <[email protected]> | ||
""" | ||
|
||
|
||
# Standard | ||
import argparse | ||
|
||
# Typing | ||
from typing import Any, Optional, Sequence, Union, cast | ||
|
||
|
||
class SubParsersAction(argparse._SubParsersAction): # pylint: disable=protected-access | ||
"""Custom SubParsersAction.""" | ||
def __call__( | ||
self, | ||
parser: argparse.ArgumentParser, | ||
namespace: argparse.Namespace, | ||
values: Union[str, Sequence[Any], None], | ||
option_string: Optional[str]=None, | ||
) -> None: | ||
"""Parses arguments with the specified subparser, then embeds the | ||
resultant sub-namespace into the supplied parent namespace. | ||
This subclass differs in functionality from the existing standard | ||
argparse SubParsersAction because it nests the resultant sub-namespace | ||
directly into the parent namespace, rather than iterating through and | ||
updating the parent namespace object with each argument individually. | ||
Example: | ||
# Create Argument Parser | ||
parser = argparse.ArgumentParser() | ||
# Add Example Global Argument | ||
parser.add_argument("--time") | ||
# Add SubParsersAction | ||
subparsers = parser.add_subparsers() | ||
# Add Example 'walk' Command with Arguments | ||
walk = subparsers.add_parser("walk") | ||
walk.add_argument("--speed") | ||
walk.add_argument("--distance") | ||
# Add Example 'talk' Command with Arguments | ||
talk = subparsers.add_parser("talk") | ||
talk.add_argument("--volume") | ||
talk.add_argument("--topic") | ||
Parsing the arguments: | ||
* --time 3 walk --speed 7 --distance 42 | ||
Resultant namespaces: | ||
* Original: Namespace(time=3, speed=7, distance=42) | ||
* Custom: Namespace(time=3, walk=Namespace(speed=7, distance=42)) | ||
This behaviour results in a final namespace structure which is much | ||
easier to parse, where subcommands are easily identified and nested | ||
into their own namespace recursively. | ||
Args: | ||
parser (argparse.ArgumentParser): Parent argument parser object. | ||
namespace (argparse.Namespace): Parent namespace being parsed to. | ||
values (Union[str, Sequence[Any], None]): Arguments to parse. | ||
option_string (Optional[str]): Optional option string (not used). | ||
Raises: | ||
argparse.ArgumentError: Raised if subparser name does not exist. | ||
""" | ||
# Check values object is a sequence | ||
# In order to not violate the Liskov Substitution Principle (LSP), the | ||
# function signature for __call__ must match the base Action class. As | ||
# such, this function signature also accepts 'str' and 'None' types for | ||
# the values argument. However, in reality, this should only ever be a | ||
# list of strings here, so we just do a type cast. | ||
values = cast(list[str], values) | ||
|
||
# Get Parser Name and Remaining Argument Strings | ||
parser_name, *arg_strings = values | ||
|
||
# Try select the parser | ||
try: | ||
# Select the parser | ||
parser = self._name_parser_map[parser_name] | ||
|
||
except KeyError as exc: | ||
# Parser doesn't exist, raise an exception | ||
raise argparse.ArgumentError( | ||
self, | ||
f"unknown parser {parser_name} (choices: {', '.join(self._name_parser_map)})" | ||
) from exc | ||
|
||
# Parse all the remaining options into a sub-namespace, then embed this | ||
# sub-namespace into the parent namespace | ||
subnamespace, arg_strings = parser.parse_known_args(arg_strings) | ||
setattr(namespace, parser_name, subnamespace) | ||
|
||
# Store any unrecognized options on the parent namespace, so that the | ||
# top level parser can decide what to do with them | ||
if arg_strings: | ||
vars(namespace).setdefault(argparse._UNRECOGNIZED_ARGS_ATTR, []) | ||
getattr(namespace, argparse._UNRECOGNIZED_ARGS_ATTR).extend(arg_strings) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -5,9 +5,9 @@ | |
@author Hayden Richards <[email protected]> | ||
""" | ||
|
||
|
||
# Local | ||
from .boolean import parse_boolean_field | ||
from .command import parse_command_field | ||
from .container import parse_container_field | ||
from .enum import parse_enum_field | ||
from .json import parse_json_field | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.