# -*- coding: utf-8 -*-
from setuptools import setup

packages = \
['datargs', 'datargs.compat']

package_data = \
{'': ['*']}

install_requires = \
['boltons>=20.2.1,<21.0.0']

extras_require = \
{':python_version == "3.6"': ['dataclasses>=0.6,<0.7'],
 'attrs': ['attrs>=20.2.0,<21.0.0']}

setup_kwargs = {
    'name': 'datargs',
    'version': '0.10.0',
    'description': 'Declarative, type-safe command line argument parsers from dataclasses and attrs classes',
    'long_description': '# datargs\n\nA paper-thin wrapper around `argparse` that creates type-safe parsers\nfrom `dataclass` and `attrs` classes.\n\n## Quickstart\n\n\nInstall `datargs`:\n\n```bash\npip install datargs\n```\n\nCreate a `dataclass` (or an `attrs` class) describing your command line interface, and call\n`datargs.parse()` with the class:\n\n```python\n# script.py\nfrom dataclasses import dataclass\nfrom pathlib import Path\nfrom datargs import parse\n\n@dataclass  # or @attr.s(auto_attribs=True)\nclass Args:\n    url: str\n    output_path: Path\n    verbose: bool\n    retries: int = 3\n\ndef main():\n    args = parse(Args)\n    print(args)\n\nif __name__ == "__main__":\n    main()\n```\n\n***(experimental)*** Alternatively: convert an existing parser to a dataclass:\n```python\n# script.py\nparser = ArgumentParser()\nparser.add_argument(...)\nfrom datargs import convert\nconvert(parser)\n```\n\n`convert()` prints a class definition to the console.\nCopy it to your script.\n\nMypy and pycharm correctly infer the type of `args` as `Args`, and your script is good to go!\n```bash\n$ python script.py -h\nusage: test.py [-h] --url URL --output-path OUTPUT_PATH [--retries RETRIES]\n               [--verbose]\n\noptional arguments:\n  -h, --help            show this help message and exit\n  --url URL\n  --output-path OUTPUT_PATH\n  --retries RETRIES\n  --verbose\n$ python script.py --url "https://..." --output-path out --retries 4 --verbose\nArgs(url="https://...", output_path=Path("out"), retries=4, verbose=True)\n```\n\n## Table of Contents\n\n<!-- toc -->\n\n- [Features](#features)\n  * [Static verification](#static-verification)\n  * [`dataclass`/`attr.s` agnostic](#dataclassattrs-agnostic)\n  * [Aliases](#aliases)\n  * [`ArgumentParser` options](#argumentparser-options)\n  * [Enums](#enums)\n  * [Sequences, Optionals, and Literals](#sequences-optionals-and-literals)\n  * [Sub Commands](#sub-commands)\n- ["Why not"s and design choices](#why-nots-and-design-choices)\n  * [Just use argparse?](#just-use-argparse)\n  * [Use `click`](#use-clickhttpsclickpalletsprojectscomen7x)?\n  * [Use `clout`](#use-clouthttpscloutreadthedocsioenlatestindexhtml)?\n  * [Use `simple-parsing`](#use-simple-parsinghttpspypiorgprojectsimple-parsing)?\n  * [Use `argparse-dataclass`](#use-argparse-dataclasshttpspypiorgprojectargparse-dataclass)?\n  * [Use `argparse-dataclasses`](#use-argparse-dataclasseshttpspypiorgprojectargparse-dataclasses)?\n- [FAQs](#faqs)\n  * [Is this cross-platform?](#is-this-cross-platform)\n  * [Why are mutually exclusive options not supported?](#why-are-mutually-exclusive-options-not-supported)\n\n<!-- tocstop -->\n\n## Features\n\n### Static verification\nMypy/Pycharm have your back when you when you make a mistake:\n```python\n...\ndef main():\n    args = parse(Args)\n    args.urll  # typo\n...\n```\nPycharm says: `Unresolved attribute reference \'urll\' for class \'Args\'`.\n\nMypy says: `script.py:15: error: "Args" has no attribute "urll"; maybe "url"?`\n\n\n### `dataclass`/`attr.s` agnostic\n```pycon\n>>> import attr, datargs\n>>> @attr.s\n... class Args:\n...     flag: bool = attr.ib()\n>>> datargs.parse(Args, [])\nArgs(flag=False)\n```\n\n### Aliases\nAliases and `ArgumentParser.add_argument()` parameters are taken from `metadata`:\n\n```pycon\n>>> from dataclasses import dataclass, field\n>>> from datargs import parse\n>>> @dataclass\n... class Args:\n...     retries: int = field(default=3, metadata=dict(help="number of retries", aliases=["-r"], metavar="RETRIES"))\n>>> parse(Args, ["-h"])\nusage: ...\noptional arguments:\n  -h, --help            show this help message and exit\n  --retries RETRIES, -r RETRIES\n>>> parse(Args, ["-r", "4"])\nArgs(retries=4)\n```\n\n`arg` is a replacement for `field` that puts `add_argument()` parameters in `metadata`.\nUse it to save precious keystrokes:\n```pycon\n>>> from dataclasses import dataclass\n>>> from datargs import parse, arg\n>>> @dataclass\n... class Args:\n...     retries: int = arg(default=3, help="number of retries", aliases=["-r"], metavar="RETRIES")\n>>> parse(Args, ["-h"])\n# exactly the same as before\n```\n\n**NOTE**: `arg()` does not currently work with `attr.s`.\n\n`arg()` also supports all `field`/`attr.ib()` keyword arguments.\n\n\n### `ArgumentParser` options\nYou can pass `ArgumnetParser` keyword arguments to `argsclass`.\nDescription is its own parameter - the rest are passed as the `parser_params` parameter as a `dict`.\n\nWhen a class is used as a subcommand (see below), `parser_params` are passed to `add_parser`, including `aliases`.\n```pycon\n>>> from datargs import parse, argsclass\n>>> @argsclass(description="Romans go home!", parser_params=dict(prog="messiah.py"))\n... class Args:\n...     flag: bool\n>>> parse(Args, ["-h"], parser=parser)\nusage: messiah.py [-h] [--flag]\nRomans go home!\n...\n```\n\nor you can pass your own parser:\n```pycon\n>>> from argparse import ArgumentParser\n>>> from datargs import parse, argsclass\n>>> @argsclass\n... class Args:\n...     flag: bool\n>>> parser = ArgumentParser(description="Romans go home!", prog="messiah.py")\n>>> parse(Args, ["-h"], parser=parser)\nusage: messiah.py [-h] [--flag]\nRomans go home!\n...\n```\n\nUse `make_parser()` to create a parser and save it for later:\n```pycon\n>>> from datargs import make_parser\n>>> @dataclass\n... class Args:\n...     ...\n>>> parser = make_parser(Args)  # pass `parser=...` to modify an existing parser\n```\n**NOTE**: passing your own parser ignores `ArgumentParser` params passed to `argsclass()`.\n\n### Enums\nWith `datargs`, enums Just Work™:\n\n```pycon\n>>> import enum, attr, datargs\n>>> class FoodEnum(enum.Enum):\n...     ham = 0\n...     spam = 1\n>>> @attr.dataclass\n... class Args:\n...     food: FoodEnum\n>>> datargs.parse(Args, ["--food", "ham"])\nArgs(food=<FoodEnum.ham: 0>)\n>>> datargs.parse(Args, ["--food", "eggs"])\nusage: enum_test.py [-h] --food {ham,spam}\nenum_test.py: error: argument --food: invalid choice: \'eggs\' (choose from [\'ham\', \'spam\'])\n```\n\n**NOTE**: enums are passed by name on the command line and not by value.\n\n## Sequences, Optionals, and Literals\nHave a `Sequence` or a `List` of something to\nautomatically use `nargs`:\n\n\n```python\nfrom pathlib import Path\nfrom dataclasses import dataclass\nfrom typing import Sequence\nfrom datargs import parse\n\n@dataclass\nclass Args:\n    # same as nargs=\'*\'\n    files: Sequence[Path] = ()\n\nargs = parse(Args, ["--files", "foo.txt", "bar.txt"])\nassert args.files == [Path("foo.txt"), Path("bar.txt")]\n```\n\nSpecify a list of positional parameters like so:\n\n```python\nfrom datargs import argsclass, arg\n@argsclass\nclass Args:\n    arg: Sequence[int] = arg(default=(), positional=True)\n```\n\n`Optional` arguments default to `None`:\n\n```python\nfrom pathlib import Path\nfrom dataclasses import dataclass\nfrom typing import Optional\nfrom datargs import parse\n\n@dataclass\nclass Args:\n    path: Optional[Path] = None\n\nargs = parse(Args, ["--path", "foo.txt"])\nassert args.path == Path("foo.txt")\n\nargs = parse(Args, [])\nassert args.path is None\n```\n\nAnd `Literal` can be used to specify choices:\n\n```python\nfrom pathlib import Path\nfrom dataclasses import dataclass\nfrom typing import Literal\nfrom datargs import parse\n\n@dataclass\nclass Args:\n    path: Literal[Path("foo.txt"), Path("bar.txt")]\n\nargs = parse(Args, ["--path", "foo.txt"])\nassert args.path == Path("foo.txt")\n\n# Throws an error!\nargs = parse(Args, ["--path", "bad-option.txt"])\n```\n\n### Sub Commands\n\nNo need to specify a useless `dest` to dispatch on different commands.\nA `Union` of dataclasses/attrs classes automatically becomes a group of subparsers.\nThe attribute holding the `Union` holds the appropriate instance\nupon parsing, making your code type-safe:\n\n```python\nimport typing, logging\nfrom datargs import argsclass, arg, parse\n\n@argsclass(description="install package")\nclass Install:\n    package: str = arg(positional=True, help="package to install")\n\n@argsclass(description="show all packages")\nclass Show:\n    verbose: bool = arg(help="show extra info")\n\n@argsclass(description="Pip Install Packages!")\nclass Pip:\n    action: typing.Union[Install, Show]\n    log: str = None\n\nargs = parse(Pip, ["--log", "debug.log", "install", "my_package"])\nprint(args)\n# prints: Pip(action=Install(package=\'my_package\'), log=\'debug.log\')\n\n# Consume arguments:\nif args.log:\n    logging.basicConfig(filename=args.log)\nif isinstance(args.action, Install):\n    install_package(args.action.package)\n    # static type error: args.action.verbose\nelif isinstance(args.action, Show):\n    list_all_packages(verbose=args.action.verbose)\nelse:\n    assert False, "Unreachable code"\n```\nCommand name is derived from class name. To change this, use the `name` parameter to `@argsclass`.\n\nAs with all other parameters to `add_parser`,\n`aliases` can be passed as a key in `parser_params` to add subcommand aliases.\n\n**NOTE**: if the commented-out line above does not issue a type error, try adding an `@dataclass/@attr.s`\nbefore or instead of `@argsclass()`:\n\n```python\n@argsclass(description="Pip Install Packages!")  # optional\n@dataclass\nclass Pip:\n    action: typing.Union[Install, Show]\n    log: str = None\n...\nif isinstance(args.action, Install):\n    install_package(args.action.package)\n    # this should now produce a type error: args.action.verbose\n```\n\n## "Why not"s and design choices\nMany libraries out there do similar things. This list serves as documentation for existing solutions and differences.\n\nSo, why not...\n\n### Just use argparse?\nThat\'s easy. The interface is clumsy and repetitive, a.k.a boilerplate. Additionally, `ArgumentParser.parse_args()` returns a `Namespace`, which is\nequivalent to `Any`, meaning that it any attribute access is legal when type checking. Alas, invalid attribute access will fail at runtime. For example:\n```python\ndef parse_args():\n    parser = ArgumentParser()\n    parser.add_argument("--url")\n    return parser.parse_args()\n\ndef main():\n    args = parse_args()\n    print(args.url)\n```\n\nLet\'s say for some reason `--url` is changed to `--uri`:\n\n```python\nparser.add_argument("--uri")\n...\nprint(args.url)  # oops\n```\nYou won\'t discover you made a mistake until you run the code. With `datargs`, a static type checker will issue an error.\nAlso, why use a carriage when you have a spaceship?\n\n### Use [`click`](https://click.palletsprojects.com/en/7.x/)?\n`click` is a great library. It provides many utilities for command line programs.\n\nUse `datargs` if you believe user interface should not be coupled with implementation, or if you\nwant to use `argparse` without boilerplate.\nUse `click` if you don\'t care.\n\n\n### Use [`clout`](https://clout.readthedocs.io/en/latest/index.html)?\nIt seems that `clout` aims to be an end-to-end solution for command line programs à la click.\n\nUse it if you need a broader solution. Use `datargs` if you want to use `argparse` without boilerplate.\n\n### Use [`simple-parsing`](https://pypi.org/project/simple-parsing/)?\nThis is another impressive library.\n\nUse it if you have deeply-nested options, or if the following points don\'t apply\nto you.\n\nUse `datargs` if you:\n* need `attrs` support\n* want as little magic as possible\n* don\'t have many options or they\'re not nested\n* prefer dashes (`--like-this`) over underscores (`--like_this`)\n\n### Use [`argparse-dataclass`](https://pypi.org/project/argparse-dataclass/)?\nIt\'s similar to this library. The main differences I found are:\n* no `attrs` support\n* not on github, so who you gonna call?\n\n### Use [`argparse-dataclasses`](https://pypi.org/project/argparse-dataclasses/)?\nSame points `argparse-dataclass` but also [Uses inheritance](https://refactoring.guru/replace-inheritance-with-delegation).\n\n## FAQs\n### Is this cross-platform?\nYes, just like `argparse`.\nIf you find a bug on a certain platform (or any other bug), please report it.\n\n### Why are mutually exclusive options not supported?\n\nThis library is based on the idea of a one-to-one correspondence between most parsers\nand simple classes. Conceptually, mutually exclusive options are analogous to\n[sum types](https://en.wikipedia.org/wiki/Tagged_union), just like [subparsers](#sub-commands) are,\nbut writing a class for each flag is not ergonomic enough.\nContact me if you want this feature or if you come up with a better solution.\n',
    'author': 'Roee Nizan',
    'author_email': 'roeen30@gmail.com',
    'maintainer': None,
    'maintainer_email': None,
    'url': 'https://github.com/roee30/datargs',
    'packages': packages,
    'package_data': package_data,
    'install_requires': install_requires,
    'extras_require': extras_require,
    'python_requires': '>=3.6,<4.0',
}


setup(**setup_kwargs)
