mivade / argparse_dataclass Goto Github PK
View Code? Open in Web Editor NEWDeclarative CLIs with argparse and dataclasses
License: MIT License
Declarative CLIs with argparse and dataclasses
License: MIT License
When building on my local machine manifest_maker
provides a warning that the MANIFEST.in
file contains unknown commands. This warning is the result of MANIFEST
not using include
statements.
Update the MANIFEST.in
file to use include
statement to ensure the following files are included in the source distribution:
README.rst
LICENSE
tox.ini
requirements_dev.txt
Makefile
rm -rf sdist/ build/ ## ensure all prior build artifacts are removed
python setup.py sdist
running sdist
running egg_info
writing argparse_dataclass.egg-info/PKG-INFO
writing dependency_links to argparse_dataclass.egg-info/dependency_links.txt
writing top-level names to argparse_dataclass.egg-info/top_level.txt
reading manifest file 'argparse_dataclass.egg-info/SOURCES.txt'
reading manifest template 'MANIFEST.in'
warning: manifest_maker: MANIFEST.in, line 1: unknown action 'README.rst'
warning: manifest_maker: MANIFEST.in, line 2: unknown action 'LICENSE'
warning: manifest_maker: MANIFEST.in, line 3: unknown action 'requirements_dev.txt'
warning: manifest_maker: MANIFEST.in, line 4: unknown action 'tox.ini'
adding license file 'LICENSE'
writing manifest file 'argparse_dataclass.egg-info/SOURCES.txt'
running check
creating argparse_dataclass-2.0.0
creating argparse_dataclass-2.0.0/argparse_dataclass.egg-info
copying files to argparse_dataclass-2.0.0...
copying LICENSE -> argparse_dataclass-2.0.0
copying MANIFEST.in -> argparse_dataclass-2.0.0
copying README.rst -> argparse_dataclass-2.0.0
copying argparse_dataclass.py -> argparse_dataclass-2.0.0
copying setup.py -> argparse_dataclass-2.0.0
copying argparse_dataclass.egg-info/PKG-INFO -> argparse_dataclass-2.0.0/argparse_dataclass.egg-info
copying argparse_dataclass.egg-info/SOURCES.txt -> argparse_dataclass-2.0.0/argparse_dataclass.egg-info
copying argparse_dataclass.egg-info/dependency_links.txt -> argparse_dataclass-2.0.0/argparse_dataclass.egg-info
copying argparse_dataclass.egg-info/top_level.txt -> argparse_dataclass-2.0.0/argparse_dataclass.egg-info
Writing argparse_dataclass-2.0.0/setup.cfg
creating dist
Creating tar archive
removing 'argparse_dataclass-2.0.0' (and everything under it)
This is like the standard dataclass
decorator but will also optionally (on by default) add a parse_args
class method to the generated class. This would allow us to do shortcuts like:
@dataclass
class Parameters:
x: int
y: int
params = Parameters.parse_args()
Consider the scenario, where an argument could have one of multiple types (see code below). Under version 0.2.1 this code worked. Now under 1.0.0 it breaks with "TypeError: Union types other than 'Optional' are not supported"
from dataclasses import dataclass, field
from typing import Union
from argparse_dataclass import ArgumentParser
def str_or_int(value: str) -> Union[str, int]:
try:
return int(value)
except ValueError:
return value
@dataclass
class Options:
str_or_int: Union[str, int] = field(metadata=dict(type=str_or_int))
parser = ArgumentParser(Options)
print(parser.parse_args(["--str-or-int", "John"]))
print(parser.parse_args(["--str-or-int", "42"]))
I think this is a legitimate use case and by having the 'type' field in metadata the user can take up the burden of transforming those. We are currently using argparse-dataclass 0.2.1 with Union types so this change in behavior is preventing us from updating at the moment.
It would be great to have this support for Union because I would really like to update and get support for Optional types as well.
To keep things simple, this could be implemented by looking for a metadata
short_option
field or similar.
Ideally we should automate pushing releases to PyPI as well.
https://www.python.org/dev/peps/pep-0541/#approval-process
seems to be the approval process to reclaim a used, but abandoned project such as args
from argparse_dataclass import dataclass
from argparse_dataclass import ArgumentParser
@dataclass
class SubOption:
a: int = 1
b: int = 2
@dataclass
class Options:
x: int = 42
y: bool = False
sub: SubOption = None
parser = ArgumentParser(Options)
x = parser.parse_args(['--sub', '1'])
print(x)
for example, how can I parse args to get a value for sub?
Not sure if you already know about this but the travis-ci.org site is being moved to travis-ci.com. The current shutdown of the org site is scheduled for June 15th. (It was pushed back form May 31)
Examples are needed in the documentation to demonstrate usage of union types (see #42).
Hi,
I seem to be running into a couple of issues when using the decorator that was recently added in #9:
from argparse_dataclass import dataclass
@dataclass(frozen=True)
class Opt:
x: int = 42
y: bool = False
Error: TypeError: cls must be a dataclass
It seems that cls
here is actually real_dataclass.wrap
.
from argparse_dataclass import dataclass
@dataclass
class Opt:
x: int = 42
y: bool = False
opt = Opt()
print(opt.x)
Error: AttributeError: 'Inner' object has no attribute 'x'
Looks like Opt
was "replaced" with Inner
, which is defined in argparse_dataclass.dataclass
.
The following class fails to parse:
@dataclass
class IndexOptsMinimal:
index: Optional[int] = None
The following workaround is required:
@dataclass
class IndexOptsWorkaround:
index: Optional[int] = field(metadata=dict(type=int), default=None)
Using optional arguments that are allowed to be None is such a common pattern that it deserves to supported implicitly.
If I create a dataclass like this:
@dataclass
class Options:
option1:int = 3
"""This is option1. it should be between 1 and 4"""
option2:str = ""
"""This is option2. it should contain a name"""
Will the docstrings appear in the help of the argparse?
Thanks for this project -- its really very handy.
Is there's support for printing help text?
I don't see dict case used in examples.
This could use some wheel packages.
Thank you for this library.
I would like to have an option that would allow to keep the underscores in the argument names instead of replacing them by minus signs. I can prepare a PR for that change if that is a feature you are happy to integrate.
Hi, it is possible to use argument groups in argparse?
This is useful when you want to group arguments together.
For example, you can group arguments by their functionality.
import argparse
parser = argparse.ArgumentParser()
group = parser.add_argument_group('Training options')
group.add_argument('--epochs', type=int, default=10, help='Number of epochs')
group.add_argument('--batch_size', type=int, default=32, help='Batch size')
group = parser.add_argument_group('Optimizer options')
group.add_argument('--lr', type=float, default=0.01, help='Learning rate')
args = parser.parse_args()
usage: train.py [-h] [--epochs EPOCHS] [--batch_size BATCH_SIZE] [--lr LR]
options:
-h, --help show this help message and exit
Training options:
--epochs EPOCHS Number of epochs
--batch_size BATCH_SIZE
Batch size
Optimizer options:
--lr LR Learning rate
Docs: https://docs.python.org/3/library/argparse.html#argument-groups
3.6 went EOL in December 2021 and 3.7 EOLs in June.
Hi,
I would like to be able to use _add_dataclass_options directly
in some of my code in order to be able to continue using normal argparse.ArgumentParser instances and use a dataclass to define only a subset of my script arguments.
Would it be possible to expose _add_dataclass_options as a public function i.e. remove the initial underscore?
With the below script, I get an exception:
from __future__ import annotations
from argparse_dataclass import dataclass
@dataclass
class MyArgs:
foo: int = 0
bar: str = 'hello'
baz: bool = False
def main():
print(MyArgs.parse_args())
if __name__ == '__main__':
main()
$ python3 targ.py
Traceback (most recent call last):
File "/Users/ibadawi/targ.py", line 4, in <module>
@dataclass
^^^^^^^^^
File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 474, in dataclass
return wrap(cls)
^^^^^^^^^
File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 465, in wrap
cls.parse_args = staticmethod(ArgumentParser(cls).parse_args)
^^^^^^^^^^^^^^^^^^^
File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 423, in __init__
_add_dataclass_options(options_class, self)
File "/Users/ibadawi/Library/Python/3.11/lib/python/site-packages/argparse_dataclass.py", line 374, in _add_dataclass_options
parser.add_argument(*args, **kwargs)
File "/usr/local/Cellar/[email protected]/3.11.2_1/Frameworks/Python.framework/Versions/3.11/lib/python3.11/argparse.py", line 1448, in add_argument
raise ValueError('%r is not callable' % (type_func,))
ValueError: 'int' is not callable
Removing from __future__ import annotations
works fine and prints MyArgs(foo=0, bar='hello', baz=False)
as expected.
It looks like the types as returned by dataclasses.fields()
are just strings in this case. I'm not super familiar with writing code to process annotations but a workaround might be to use typing.get_type_hints()
instead of dataclasses.fields()
to get at the field types:
typing.get_type_hints(MyArgs):
{'bar': <class 'str'>, 'baz': <class 'bool'>, 'foo': <class 'int'>}
dataclasses.fields(MyArgs):
(Field(name='foo',type='int',default=0,default_factory=<dataclasses._MISSING_TYPE object at 0x10b1d5610>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD),
Field(name='bar',type='str',default='hello',default_factory=<dataclasses._MISSING_TYPE object at 0x10b1d5610>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD),
Field(name='baz',type='bool',default=False,default_factory=<dataclasses._MISSING_TYPE object at 0x10b1d5610>,init=True,repr=True,hash=None,compare=True,metadata=mappingproxy({}),kw_only=False,_field_type=_FIELD))
example code:
from dataclasses import dataclass, field
from argparse_dataclass import ArgumentParser
from argparse import ArgumentDefaultsHelpFormatter
@dataclass
class FineParams:
batch_size: int = field(default=300)
parser = ArgumentParser(GCPFineParams, formatter_class=ArgumentDefaultsHelpFormatter)
params: FineParams = parser.parse_args()
resulting non-defaults help printout.
diving into argparse code (argparse.py, ver 1.1, line 1861) shone that the ArgumentParser's _actions
class members, batch_size
action is stored as _StoreAction(option_strings=['--batch-size'], dest='batch_size', nargs=None, const=None, default=<dataclasses._MISSING_TYPE object at 0x7f8465889960>, type=<class 'int'>, choices=None, required=False, help=None, metavar=None)
Since I am in the happy position of building a school project and not being able to depend on click for command-line arguments, I decided to see if it was possible to combine dataclasses and argparse. Apparently your library (which I would have to rewrite anyway) doesn't make it possible to provide positional arguments. Would that be possible through another metadata flag?
I don't know if this is the right place to write, but I don't know where else write it, anyway....
Are you intending to publish the lib again on pypi? I found this library very useful and it could be worth!
Thanks in advance
We're still using setup.py
but a pyproject.toml
-based approach is the preferred way these days. See also build.
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.