No project description provided
Project description
aparse
Python argparse extension with support for typing.
Getting started
Install the library from pip:
$ pip install aparse
Extend a function with @add_argparse_arguments
decorator to add arguments automatically:
import argparse
from aparse import add_argparse_arguments
@add_argparse_arguments()
def example(arg1: str, arg2: int = 5):
pass
parser = argparse.ArgumentParser()
parser = example.add_argparse_arguments(parser)
args = parser.parse_args()
# Call example with args
example.from_argparse_arguments(args)
Extend a class with @add_argparse_arguments
decorator to construct it automatically:
import argparse
from aparse import add_argparse_arguments
@add_argparse_arguments()
class Example:
def __init__(self, arg1: str, arg2: int = 5):
pass
parser = argparse.ArgumentParser()
parser = Example.add_argparse_arguments(parser)
args = parser.parse_args()
# Construct Example with args
instance = Example.from_argparse_arguments(args)
Advanced usage
Using class inheritance
Arguments are automatically added from all base classes if kwargs or args arguments are used in the constructor.
import argparse
from aparse import add_argparse_arguments
class Parent:
def __init__(self, arg3: str = 'test'):
pass
@add_argparse_arguments()
class Example(Parent):
def __init__(arg1: str, arg2: int = 5, **kwargs):
super().__init__(**kwargs)
parser = argparse.ArgumentParser()
parser = Example.add_argparse_arguments(parser)
args = parser.parse_args()
# Construct Example with args
instance = Example.from_argparse_arguments(args)
Using arguments with the same name
Arguments can be reused if they share the same name.
If the types are same and none or only one of them has a default parameter
the arguments are merged automatically. If both arguments have a different type
or a different values, exception is raised by default. You can prevent this
behavior by using soft_defaults=True
when calling add_argparse_arguments
.
import argparse
from aparse import add_argparse_arguments
@add_argparse_arguments()
def example1(arg1: str, arg2: int = 5):
pass
@add_argparse_arguments()
def example2(arg1: str = 'test', arg2: int = 5):
pass
parser = argparse.ArgumentParser()
parser = example1.add_argparse_arguments(parser)
parser = example2.add_argparse_arguments(parser)
args = parser.parse_args()
# Call example1 and example2 with args
example1.from_argparse_arguments(args)
example2.from_argparse_arguments(args)
Using prefixes
Prefixes can be used to separate otherwise incompatible parameters.
import argparse
from aparse import add_argparse_arguments
@add_argparse_arguments()
def example1(arg1: str, arg2: int = 3):
pass
@add_argparse_arguments()
def example2(arg1: str = 'test', arg2: int = 5):
pass
parser = argparse.ArgumentParser()
parser = example1.add_argparse_arguments(parser, prefix='ex1')
parser = example2.add_argparse_arguments(parser, prefix='ex2')
args = parser.parse_args()
# Call example1 and example2 with args
example1.from_argparse_arguments(args, _prefix='ex1')
example2.from_argparse_arguments(args, _prefix='ex2')
Getting raw argparse arguments
If you need access to the raw arguments, you can use aparse.ArgparseArguments
,
in which case, the argparse arguments are passed as a dictionary.
import argparse
from aparse import add_argparse_arguments, ArgparseArguments
@add_argparse_arguments()
def example(ArgparseArguments: args):
pass
parser = argparse.ArgumentParser()
parser = example.add_argparse_arguments(parser)
args = parser.parse_args()
# Call example with args
example.from_argparse_arguments(args)
Using nested dataclasses as arguments
Dataclasses are expanded as other argparse arguments. You can even have nested dataclasses.
@dataclass
class D1:
test: str
@add_argparse_arguments()
@dataclass
class D2:
data1: D1
test2: int
argparser = ArgumentParser()
D2.add_argparse_arguments(argparser)
args = argparser.parse_args(['--test2', '5', '--data1-test', 'ok'])
d2 = D2.from_argparse_arguments(args)
List arguments
Lists can be used as arguments. In that case, the values are separated by commas.
@add_argparse_arguments()
def test_fn(d: List[int], e: List[str]):
return d, e
argparser = ArgumentParser()
test_fn.add_argparse_arguments(argparser)
args = argparser.parse_args(['--d', '2,3', '--e', 'te,st'])
d, e = test_fn.from_argparse_arguments(args)
Custom code to construct class from string
If needed, you can specify, how the argument's class instance is constructed from a string argument.
class CS:
def __init__(self, a):
self.a = a
@staticmethod
def from_str(str_val):
return CS(f'ok-{str_val}')
@add_argparse_arguments()
def test_fn(d: CS):
return d
argparser = ArgumentParser()
test_fn.add_argparse_arguments(argparser)
args = argparser.parse_args(['--d', 'test'])
d = test_fn.from_argparse_arguments(args)
Getting the parsed arguments
In order to obtain the parsed kwargs without calling your function,
use the bind_argparse_arguments
function.
@add_argparse_arguments()
def testfn(k: int = 1, m: float = 2.):
return dict(k=k, m=m)
argparser = ArgumentParser()
argparser = testfn.add_argparse_arguments(argparser)
args = argparser.parse_args(['--k', '3'])
kwargs = testfn.bind_argparse_arguments(args)
Passing other arguments to from_argparse_arguments
By defaults, aparse forwards any arguments passed to the
from_argparse_arguments
function to the original function.
If the name is the same as an already existing argparse argument,
its value is replaced by the value passed to the from_argparse_arguments
function.
@add_argparse_arguments()
def testfn(x, k: int = 1, m: float = 2.):
return dict(k=k, m=m, x=x)
argparser = ArgumentParser()
argparser = testfn.add_argparse_arguments(argparser)
args = argparser.parse_args(['--k', '3'])
testfn.from_argparse_arguments(args, 'test', m=5)
Ignoring arguments
Arguments can be ignored as follows:
@add_argparse_arguments(ignore={'m'})
def testfn(k: int = 1, m: float = 2.):
return dict(k=k, m=m)
argparser = ArgumentParser()
argparser = testfn.add_argparse_arguments(argparser)
args = argparser.parse_args(['--k', '3'])
testfn.from_argparse_arguments(args)
Extending aparse
You can extend the basic handling of the aparse library, e.g., to
add your own types. Implement your own aparse.Handler
and register
it with aparse.register_handler
decorator.
For example the following code is the handler used for parsing lists.
from aparse import Handler, register_handler
@register_handler
class SimpleListHandler(Handler):
def _list_type(self, tp: Type):
if getattr(tp, '__origin__', None) == list:
tp = tp.__args__[0]
if tp in (int, str, float):
return tp
return None
def preprocess_argparse_parameter(self, parameter: Parameter) -> Type:
if self._list_type(parameter.type) is not None:
return True, dataclasses.replace(parameter, argument_type=str)
return False, parameter
def parse_value(self, parameter: Parameter, value: Any) -> Any:
list_type = self._list_type(parameter.type)
if list_type is not None and isinstance(value, str):
return True, list(map(list_type, value.split(',')))
return False, value
Registering callbacks before and after parse
This functionality is currently under construction.
Conditional parsing
This functionality is currently under construction.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
File details
Details for the file aparse-0.0.3.tar.gz
.
File metadata
- Download URL: aparse-0.0.3.tar.gz
- Upload date:
- Size: 10.9 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.2 CPython/3.9.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | fb6aaa82e5d99f2ec29e66f6b06ce919680efda071a87d020075961c542569e1 |
|
MD5 | 671396230ff550b7775ec70016fa5166 |
|
BLAKE2b-256 | 02d1ec99bcebfed2b82958ada218bffc831862712a54dbc3a451afed3be36e96 |
File details
Details for the file aparse-0.0.3-py3-none-any.whl
.
File metadata
- Download URL: aparse-0.0.3-py3-none-any.whl
- Upload date:
- Size: 10.2 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/3.4.2 importlib_metadata/4.8.1 pkginfo/1.7.1 requests/2.26.0 requests-toolbelt/0.9.1 tqdm/4.62.2 CPython/3.9.6
File hashes
Algorithm | Hash digest | |
---|---|---|
SHA256 | b271e2876c075c16c1c110294a843c7ea5176291442c827176d1205a7fb0d92a |
|
MD5 | 5099bf4845165c8f496d6147601f7c26 |
|
BLAKE2b-256 | 8d41951ab82718ccf7e7af027d8a05eb61d3e1179dc44a0141deaa0869a8e4a5 |