pydargs


Namepydargs JSON
Version 0.11.0 PyPI version JSON
download
home_pageNone
SummaryEasily configure a CLI application using a (Pydantic) dataclass.
upload_time2024-04-04 11:19:45
maintainerNone
docs_urlNone
authorNone
requires_python>=3.9
licenseBSD
keywords cli dataclass
VCS
bugtrack_url
requirements No requirements were recorded.
Travis-CI No Travis.
coveralls test coverage No coveralls.
            # pydargs

Easily configure a CLI application using a (Pydantic) dataclass.

## Usage

Pydargs instantiates a dataclass that is used as (configuration) input of your entrypoint from command line arguments.
For example, in `example.py`:

```python
from dataclasses import dataclass
from pydargs import parse


@dataclass
class Config:
    number: int
    some_string: str = "abc"


def main(config: Config) -> None:
    """Your main functionality"""
    print(f"> Hello {config.number} + {config.some_string}")


if __name__ == "__main__":
    config = parse(Config)
    main(config)
```

Here the `Config` dataclass serves as input (configuration) of the `main` function. Pydargs facilitates
instantiating the `config` instance, allowing the user to use command line arguments to set or override the
values of its fields:


```shell
$ python example.py --number 1
> Hello 1 abc
$ python example.py --number 2 --some-string def
> Hello 2 def
$ python example.py --help
usage: example.py [-h] --number NUMBER [--some-string SOME_STRING]

options:
  -h, --help            show this help message and exit
  --number NUMBER
  --some-string SOME_STRING
                        (default: abc)
```

This saves you from having to maintain boilerplate code such as

```python
from argparse import ArgumentParser
from dataclasses import dataclass


@dataclass
class Config:
    number: int
    some_string: str = "abc"


def main(config: Config) -> None:
    """Your main functionality"""
    print(f"> Hello {config.number} + {config.some_string}")


if __name__ == "__main__":
    parser = ArgumentParser()
    parser.add_argument("--number", type=int)
    parser.add_argument("--some-string", dest="some_string", default="abc")
    namespace = parser.parse_args()
    config = Config(number=namespace["number"], some_string=namespace["some_string"])
    main(config)
```

Aside from that, pydargs supports:
- [a wide variety of field types](#supported-field-types),
- [nested dataclasses](#nested-dataclasses),
- [subparsers / commands](#subparsers),
- [pydantic dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/) to help you with validation.

## Installation

Pydargs can be installed with your favourite package manager. For example:

```
pip install pydargs
```

## ArgumentParser arguments

It's possible to pass additional arguments to the underlying `argparse.ArgumentParser` instance by providing them
as keyword arguments to the `parse` function. For example:

```python
config = parse(Config, prog="myprogram", allow_abbrev=False)
```
will disable abbreviations for long options and set the program name to `myprogram` in help messages. For an extensive list of accepted arguments, see [the argparse docs](https://docs.python.org/3/library/argparse.html#argumentparser-objects).

## Supported Field Types

The dataclass can have fields of the base types: `int`, `float`, `str`, `bool`, as well as:

- **Literals** comprised of those types.
- **Enums**, although these
  are [not recommended](https://docs.python.org/3/library/argparse.html#choices) as they do not play nice in the help
  messages. Only the enum _name_ is accepted as a valid input, not the _value_.
- **Bytes**, with an optional `encoding` metadata field:
  `a_value: bytes = field(metadata=dict(encoding="ascii"))`, which defaults to utf-8.
- **Date** and **datetime**, with an optional `date_format` metadata
  field: `your_date: date = field(metadata=dict(date_format="%m-%d-%Y"))`. When not
  provided dates in ISO 8601 format are accepted.
- **Lists** of those types, either denoted as e.g. `list[int]` or `Sequence[int]`.
  Multiple arguments to a `numbers: list[int]` field can be provided as `--numbers 1 2 3`.
  A list-field without a default will require at least a single value to be provided.
  If a default is provided, it will be completely replaced by any arguments, if provided.
- **Optional types**, denoted as e.g. `typing.Optional[int]` or `int | None` (for Python 3.10 and above).
  Any argument passed is assumed to be of the provided type and can never be `None`.
- **Unions of types**, denoted as e.g. `typing.Union[int, str]` or `int | str`. Each argument
  will be parsed into the first type that returns a valid result. Note that this means
  that `str | int` will _always_ result in a value of type `str`.
- Any other type that can be instantiated from a string, such as `Path`.
- Dataclasses that, in turn, contain fields of supported types. See [Nested Dataclasses](#nested-dataclasses).
- A union of multiple dataclasses, that in turn contain fields of supported types,
  which will be parsed in [Subparsers](#subparsers).

## Overriding defaults from a file

Pydargs can also consume values from a JSON- or YAML-formatted file. To enable
this, pass `add_config_file_argument=True` to the `parse` function, which will add a `--config-file`
command line argument. If provided, the values from this file will override the defaults
of the dataclass fields. Any command line arguments passed will override the
defaults provided in the file.

For example, with the following contents in `defaults.json`:

```json
{
  "a": 1,
  "b": "abc"
}
```

then running this code

```python
from dataclasses import dataclass
from pydargs import parse


@dataclass
class Config:
  a: int = 2
  b: str = "def"


if __name__ == "__main__":
  config = parse(Config, add_config_file_argument=True)
```

with the following arguments

`entrypoint --config-file defaults.json --b xyz`

would result in `Config(a=1, b="xyz")`.

Note that:
- Only _defaults_ can be overridden. Any dataclass fields without a default must always be provided on the command line.
- Any extra keys present inside the file but not matching a field in the dataclass will be ignored,
  and if any are present a warning will be raised.
- In order to load defaults from a YAML-formatted file, [PyYAML](https://pyyaml.org/wiki/PyYAMLDocumentation) has
  to be installed. To install it with pydargs, run `pip install pydargs[pyyaml]`.
- The parsed dataclass may not have a field named `config_file`.
- The defaults provided in the file will not be type-casted by pydargs, and hence only JSON-native types are supported.

## Metadata

Additional options can be provided to the dataclass field metadata.

The following metadata fields are supported:

### `positional`
Set `positional=True` to create a positional argument instead of an option.

```python
from dataclasses import dataclass, field

@dataclass
class Config:
  argument: str = field(metadata=dict(positional=True))
```


### `as_flags`

Set `as_flags=True` for a boolean field:
```python
from dataclasses import dataclass, field

@dataclass
class Config:
  verbose: bool = field(default=False, metadata=dict(as_flags=True))
```
which would create the arguments `--verbose` and `--no-verbose` to
set the value of `verbose` to `True` or `False` respectively, instead
of a single option that requires a value like `--verbose True`.

### `parser`

Provide a custom type converter that parses the argument into the desired type. For example:

```python
from dataclasses import dataclass, field
from json import loads

@dataclass
class Config:
  list_of_numbers: list[int] = field(metadata=dict(parser=loads))
```

This would parse `--list-of-numbers [1, 2, 3]` into the list `[1, 2, 3]`. Note that the error message returned
when providing invalid input is lacking any details. Also, no validation is performed to verify that the returned
type matches the field type. In the above example, `--list-of-numbers '{"a": "b"}'` would result in `list_of_numbers`
being the dictionary `{"a": "b"}` without any kind of warning.

### `short_option`

Provide a short option for a field, which can be used as an alternative to the long option.
For example,

```python
from dataclasses import dataclass, field

@dataclass
class Config:
  a_field_with_a_long_name: int = field(metadata=dict(short_option="-a"))
```

would allow using `-a 42` as an alternative to `--a-field-with-a-long-name 42`.

### Ignoring fields
Fields can be ignored by adding the `ignore_arg` metadata field:

```python
@dataclass
class Config:
    number: int
    ignored: str = field(metadata=dict(ignore_arg=True))
```
When indicated, this field is not added to the parser and cannot be overridden with an argument.

### Fields excluded from the `__init__()`
Fields not included in the `__init__()` (i.e. with `init=False`, see [here](https://docs.python.org/3/library/dataclasses.html#dataclasses.field) ) will be ignored by pydargs and cannot be overridden with an argument.

```python
@dataclass
class Config:
    number: int
    ignored: str = field(init=False)
```

This could be useful in combination with a [`__post_init__()` method](https://docs.python.org/3/library/dataclasses.html#post-init-processing) to set the value of the field.


### `help`

Provide a brief description of the field, used in the help messages generated by argparse.
For example, calling `your_program -h` with the dataclass below,

```python
from dataclasses import dataclass, field

@dataclass
class Config:
  an_integer: int = field(metadata=dict(help="any integer you like"))
```

would result in a message like:

```text
usage: your_program [-h] [--an-integer AN_INTEGER]

optional arguments:
  -h, --help               show this help message and exit
  --an-integer AN_INTEGER  any integer you like
```

### `metavar`

Override the displayed name of an argument in the help messages generated by argparse,
as documented [here](https://docs.python.org/3/library/argparse.html#metavar).

For example, with the following dataclass,
```python
from dataclasses import dataclass, field

@dataclass
class Config:
  an_integer: int = field(metadata=dict(metavar="INT"))
```
calling `your_program -h` would result in a message like:

```text
usage: your_program [-h] [--an-integer INT]

optional arguments:
  -h, --help        show this help message and exit
  --an-integer INT
```

## Nested Dataclasses

Dataclasses may be nested; the type of a dataclass field may be another dataclass type:

```python
from dataclasses import dataclass

@dataclass
class Config:
  field_a: int
  field_b: str = "abc"


@dataclass
class Base:
  config: Config
  verbose: bool = False
```

Argument names of fields of the nested dataclass are prefixed with the field name of the nested dataclass in the base
dataclass. Calling `pydargs.parse(Base, ["-h"])` will result in something like:

```text
usage: your_program.py [-h] --config-field-a CONFIG_FIELD_A
                            [--config-field-b CONFIG_FIELD_B]
                            [--verbose VERBOSE]

options:
  -h, --help            show this help message and exit
  --verbose VERBOSE     (default: False)

config:
  --config-field-a CONFIG_FIELD_A
  --config-field-b CONFIG_FIELD_B
                        (default: abc)

```

Please be aware of the following:
- The default (factory) of fields with a dataclass type is ignored by pydargs, which may yield unexpected results.
  E.g., in the example above, `config: Config = field(default_factory=lambda: Config(field_b="def"))` will not result in a default of "def" for field_b when parsed by pydargs.
  Instead, set `field_b: str = "def"` in the definition of `Config`.
  If you must add a default, for example for instantiating your dataclass elsewhere, do `config: Config = field(default_factory=Config)`, assuming that all fields in `Config` have a default.
- Nested dataclasses can not be positional (although _fields of_ the nested dataclass can be).
- Argument names must not collide. In the example above, the `Base` class should not contain a field named `config_field_a`.
- When reading [defaults from a file](#loading-defaults-from-file), the data inside the file may be nested like the dataclasses as well as flat with prefixes.
  E.g. `{"config": {"field_b": "xyz"}` has the same effect as `{"config_field_b": "xyz"}`. Pydargs will raise an
  exception in the case of collisions between keys in alternative formats.

## Subparsers

Dataclasses can contain a field with a union-of-dataclasses type, e.g.:

```python
from dataclasses import dataclass, field
from typing import Union


@dataclass
class Command1:
  field_a: int
  field_b: str = "abc"


@dataclass
class Command2:
  field_c: str = field(metadata=dict(positional=True))


@dataclass
class Base:
  command: Union[Command1, Command2]
  verbose: bool = False
```

This will result in [sub commands](https://docs.python.org/3/library/argparse.html#sub-commands)
which allow calling your entrypoint as `entrypoint --verbose Command1 --field-a 12`.

Calling `pydargs.parse(Base, ["-h"])` will result in something like:

```text
usage: your_program.py [-h] [--verbose VERBOSE] {Command1,command1,Command2,command2} ...

options:
  -h, --help            show this help message and exit
  --verbose VERBOSE     (default: False)

action:
  {Command1,command1,Command2,command2}
```

Note that:
- Also lower-case command names are accepted.
- Any dataclass can not contain more than one subcommand-field.
- Sub-commands can be nested and mixed with nested dataclasses.
- Any positional fields defined after a subcommand-field can not be parsed.
- Subparsers handle all arguments that come after the command; so all global arguments must come before the command.
  In the above example this means that  `entrypoint --verbose Command2 string`
  is valid but `entrypoint Command2 string --verbose` is not.

            

Raw data

            {
    "_id": null,
    "home_page": null,
    "name": "pydargs",
    "maintainer": null,
    "docs_url": null,
    "requires_python": ">=3.9",
    "maintainer_email": null,
    "keywords": "cli, dataclass",
    "author": null,
    "author_email": "Anton Steenvoorden <Anton.Steenvoorden@ah.nl>, Guus Verstegen <gjaverstegen@gmail.com>, Rogier van der Geer <rogier@vander-geer.nl>",
    "download_url": "https://files.pythonhosted.org/packages/a8/8f/f88b092c6876a4437a9366a9954997293ba79a8b1f1c471b3a8e5f6bd361/pydargs-0.11.0.tar.gz",
    "platform": null,
    "description": "# pydargs\n\nEasily configure a CLI application using a (Pydantic) dataclass.\n\n## Usage\n\nPydargs instantiates a dataclass that is used as (configuration) input of your entrypoint from command line arguments.\nFor example, in `example.py`:\n\n```python\nfrom dataclasses import dataclass\nfrom pydargs import parse\n\n\n@dataclass\nclass Config:\n    number: int\n    some_string: str = \"abc\"\n\n\ndef main(config: Config) -> None:\n    \"\"\"Your main functionality\"\"\"\n    print(f\"> Hello {config.number} + {config.some_string}\")\n\n\nif __name__ == \"__main__\":\n    config = parse(Config)\n    main(config)\n```\n\nHere the `Config` dataclass serves as input (configuration) of the `main` function. Pydargs facilitates\ninstantiating the `config` instance, allowing the user to use command line arguments to set or override the\nvalues of its fields:\n\n\n```shell\n$ python example.py --number 1\n> Hello 1 abc\n$ python example.py --number 2 --some-string def\n> Hello 2 def\n$ python example.py --help\nusage: example.py [-h] --number NUMBER [--some-string SOME_STRING]\n\noptions:\n  -h, --help            show this help message and exit\n  --number NUMBER\n  --some-string SOME_STRING\n                        (default: abc)\n```\n\nThis saves you from having to maintain boilerplate code such as\n\n```python\nfrom argparse import ArgumentParser\nfrom dataclasses import dataclass\n\n\n@dataclass\nclass Config:\n    number: int\n    some_string: str = \"abc\"\n\n\ndef main(config: Config) -> None:\n    \"\"\"Your main functionality\"\"\"\n    print(f\"> Hello {config.number} + {config.some_string}\")\n\n\nif __name__ == \"__main__\":\n    parser = ArgumentParser()\n    parser.add_argument(\"--number\", type=int)\n    parser.add_argument(\"--some-string\", dest=\"some_string\", default=\"abc\")\n    namespace = parser.parse_args()\n    config = Config(number=namespace[\"number\"], some_string=namespace[\"some_string\"])\n    main(config)\n```\n\nAside from that, pydargs supports:\n- [a wide variety of field types](#supported-field-types),\n- [nested dataclasses](#nested-dataclasses),\n- [subparsers / commands](#subparsers),\n- [pydantic dataclasses](https://docs.pydantic.dev/latest/concepts/dataclasses/) to help you with validation.\n\n## Installation\n\nPydargs can be installed with your favourite package manager. For example:\n\n```\npip install pydargs\n```\n\n## ArgumentParser arguments\n\nIt's possible to pass additional arguments to the underlying `argparse.ArgumentParser` instance by providing them\nas keyword arguments to the `parse` function. For example:\n\n```python\nconfig = parse(Config, prog=\"myprogram\", allow_abbrev=False)\n```\nwill disable abbreviations for long options and set the program name to `myprogram` in help messages. For an extensive list of accepted arguments, see [the argparse docs](https://docs.python.org/3/library/argparse.html#argumentparser-objects).\n\n## Supported Field Types\n\nThe dataclass can have fields of the base types: `int`, `float`, `str`, `bool`, as well as:\n\n- **Literals** comprised of those types.\n- **Enums**, although these\n  are [not recommended](https://docs.python.org/3/library/argparse.html#choices) as they do not play nice in the help\n  messages. Only the enum _name_ is accepted as a valid input, not the _value_.\n- **Bytes**, with an optional `encoding` metadata field:\n  `a_value: bytes = field(metadata=dict(encoding=\"ascii\"))`, which defaults to utf-8.\n- **Date** and **datetime**, with an optional `date_format` metadata\n  field: `your_date: date = field(metadata=dict(date_format=\"%m-%d-%Y\"))`. When not\n  provided dates in ISO 8601 format are accepted.\n- **Lists** of those types, either denoted as e.g. `list[int]` or `Sequence[int]`.\n  Multiple arguments to a `numbers: list[int]` field can be provided as `--numbers 1 2 3`.\n  A list-field without a default will require at least a single value to be provided.\n  If a default is provided, it will be completely replaced by any arguments, if provided.\n- **Optional types**, denoted as e.g. `typing.Optional[int]` or `int | None` (for Python 3.10 and above).\n  Any argument passed is assumed to be of the provided type and can never be `None`.\n- **Unions of types**, denoted as e.g. `typing.Union[int, str]` or `int | str`. Each argument\n  will be parsed into the first type that returns a valid result. Note that this means\n  that `str | int` will _always_ result in a value of type `str`.\n- Any other type that can be instantiated from a string, such as `Path`.\n- Dataclasses that, in turn, contain fields of supported types. See [Nested Dataclasses](#nested-dataclasses).\n- A union of multiple dataclasses, that in turn contain fields of supported types,\n  which will be parsed in [Subparsers](#subparsers).\n\n## Overriding defaults from a file\n\nPydargs can also consume values from a JSON- or YAML-formatted file. To enable\nthis, pass `add_config_file_argument=True` to the `parse` function, which will add a `--config-file`\ncommand line argument. If provided, the values from this file will override the defaults\nof the dataclass fields. Any command line arguments passed will override the\ndefaults provided in the file.\n\nFor example, with the following contents in `defaults.json`:\n\n```json\n{\n  \"a\": 1,\n  \"b\": \"abc\"\n}\n```\n\nthen running this code\n\n```python\nfrom dataclasses import dataclass\nfrom pydargs import parse\n\n\n@dataclass\nclass Config:\n  a: int = 2\n  b: str = \"def\"\n\n\nif __name__ == \"__main__\":\n  config = parse(Config, add_config_file_argument=True)\n```\n\nwith the following arguments\n\n`entrypoint --config-file defaults.json --b xyz`\n\nwould result in `Config(a=1, b=\"xyz\")`.\n\nNote that:\n- Only _defaults_ can be overridden. Any dataclass fields without a default must always be provided on the command line.\n- Any extra keys present inside the file but not matching a field in the dataclass will be ignored,\n  and if any are present a warning will be raised.\n- In order to load defaults from a YAML-formatted file, [PyYAML](https://pyyaml.org/wiki/PyYAMLDocumentation) has\n  to be installed. To install it with pydargs, run `pip install pydargs[pyyaml]`.\n- The parsed dataclass may not have a field named `config_file`.\n- The defaults provided in the file will not be type-casted by pydargs, and hence only JSON-native types are supported.\n\n## Metadata\n\nAdditional options can be provided to the dataclass field metadata.\n\nThe following metadata fields are supported:\n\n### `positional`\nSet `positional=True` to create a positional argument instead of an option.\n\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass Config:\n  argument: str = field(metadata=dict(positional=True))\n```\n\n\n### `as_flags`\n\nSet `as_flags=True` for a boolean field:\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass Config:\n  verbose: bool = field(default=False, metadata=dict(as_flags=True))\n```\nwhich would create the arguments `--verbose` and `--no-verbose` to\nset the value of `verbose` to `True` or `False` respectively, instead\nof a single option that requires a value like `--verbose True`.\n\n### `parser`\n\nProvide a custom type converter that parses the argument into the desired type. For example:\n\n```python\nfrom dataclasses import dataclass, field\nfrom json import loads\n\n@dataclass\nclass Config:\n  list_of_numbers: list[int] = field(metadata=dict(parser=loads))\n```\n\nThis would parse `--list-of-numbers [1, 2, 3]` into the list `[1, 2, 3]`. Note that the error message returned\nwhen providing invalid input is lacking any details. Also, no validation is performed to verify that the returned\ntype matches the field type. In the above example, `--list-of-numbers '{\"a\": \"b\"}'` would result in `list_of_numbers`\nbeing the dictionary `{\"a\": \"b\"}` without any kind of warning.\n\n### `short_option`\n\nProvide a short option for a field, which can be used as an alternative to the long option.\nFor example,\n\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass Config:\n  a_field_with_a_long_name: int = field(metadata=dict(short_option=\"-a\"))\n```\n\nwould allow using `-a 42` as an alternative to `--a-field-with-a-long-name 42`.\n\n### Ignoring fields\nFields can be ignored by adding the `ignore_arg` metadata field:\n\n```python\n@dataclass\nclass Config:\n    number: int\n    ignored: str = field(metadata=dict(ignore_arg=True))\n```\nWhen indicated, this field is not added to the parser and cannot be overridden with an argument.\n\n### Fields excluded from the `__init__()`\nFields not included in the `__init__()` (i.e. with `init=False`, see [here](https://docs.python.org/3/library/dataclasses.html#dataclasses.field) ) will be ignored by pydargs and cannot be overridden with an argument.\n\n```python\n@dataclass\nclass Config:\n    number: int\n    ignored: str = field(init=False)\n```\n\nThis could be useful in combination with a [`__post_init__()` method](https://docs.python.org/3/library/dataclasses.html#post-init-processing) to set the value of the field.\n\n\n### `help`\n\nProvide a brief description of the field, used in the help messages generated by argparse.\nFor example, calling `your_program -h` with the dataclass below,\n\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass Config:\n  an_integer: int = field(metadata=dict(help=\"any integer you like\"))\n```\n\nwould result in a message like:\n\n```text\nusage: your_program [-h] [--an-integer AN_INTEGER]\n\noptional arguments:\n  -h, --help               show this help message and exit\n  --an-integer AN_INTEGER  any integer you like\n```\n\n### `metavar`\n\nOverride the displayed name of an argument in the help messages generated by argparse,\nas documented [here](https://docs.python.org/3/library/argparse.html#metavar).\n\nFor example, with the following dataclass,\n```python\nfrom dataclasses import dataclass, field\n\n@dataclass\nclass Config:\n  an_integer: int = field(metadata=dict(metavar=\"INT\"))\n```\ncalling `your_program -h` would result in a message like:\n\n```text\nusage: your_program [-h] [--an-integer INT]\n\noptional arguments:\n  -h, --help        show this help message and exit\n  --an-integer INT\n```\n\n## Nested Dataclasses\n\nDataclasses may be nested; the type of a dataclass field may be another dataclass type:\n\n```python\nfrom dataclasses import dataclass\n\n@dataclass\nclass Config:\n  field_a: int\n  field_b: str = \"abc\"\n\n\n@dataclass\nclass Base:\n  config: Config\n  verbose: bool = False\n```\n\nArgument names of fields of the nested dataclass are prefixed with the field name of the nested dataclass in the base\ndataclass. Calling `pydargs.parse(Base, [\"-h\"])` will result in something like:\n\n```text\nusage: your_program.py [-h] --config-field-a CONFIG_FIELD_A\n                            [--config-field-b CONFIG_FIELD_B]\n                            [--verbose VERBOSE]\n\noptions:\n  -h, --help            show this help message and exit\n  --verbose VERBOSE     (default: False)\n\nconfig:\n  --config-field-a CONFIG_FIELD_A\n  --config-field-b CONFIG_FIELD_B\n                        (default: abc)\n\n```\n\nPlease be aware of the following:\n- The default (factory) of fields with a dataclass type is ignored by pydargs, which may yield unexpected results.\n  E.g., in the example above, `config: Config = field(default_factory=lambda: Config(field_b=\"def\"))` will not result in a default of \"def\" for field_b when parsed by pydargs.\n  Instead, set `field_b: str = \"def\"` in the definition of `Config`.\n  If you must add a default, for example for instantiating your dataclass elsewhere, do `config: Config = field(default_factory=Config)`, assuming that all fields in `Config` have a default.\n- Nested dataclasses can not be positional (although _fields of_ the nested dataclass can be).\n- Argument names must not collide. In the example above, the `Base` class should not contain a field named `config_field_a`.\n- When reading [defaults from a file](#loading-defaults-from-file), the data inside the file may be nested like the dataclasses as well as flat with prefixes.\n  E.g. `{\"config\": {\"field_b\": \"xyz\"}` has the same effect as `{\"config_field_b\": \"xyz\"}`. Pydargs will raise an\n  exception in the case of collisions between keys in alternative formats.\n\n## Subparsers\n\nDataclasses can contain a field with a union-of-dataclasses type, e.g.:\n\n```python\nfrom dataclasses import dataclass, field\nfrom typing import Union\n\n\n@dataclass\nclass Command1:\n  field_a: int\n  field_b: str = \"abc\"\n\n\n@dataclass\nclass Command2:\n  field_c: str = field(metadata=dict(positional=True))\n\n\n@dataclass\nclass Base:\n  command: Union[Command1, Command2]\n  verbose: bool = False\n```\n\nThis will result in [sub commands](https://docs.python.org/3/library/argparse.html#sub-commands)\nwhich allow calling your entrypoint as `entrypoint --verbose Command1 --field-a 12`.\n\nCalling `pydargs.parse(Base, [\"-h\"])` will result in something like:\n\n```text\nusage: your_program.py [-h] [--verbose VERBOSE] {Command1,command1,Command2,command2} ...\n\noptions:\n  -h, --help            show this help message and exit\n  --verbose VERBOSE     (default: False)\n\naction:\n  {Command1,command1,Command2,command2}\n```\n\nNote that:\n- Also lower-case command names are accepted.\n- Any dataclass can not contain more than one subcommand-field.\n- Sub-commands can be nested and mixed with nested dataclasses.\n- Any positional fields defined after a subcommand-field can not be parsed.\n- Subparsers handle all arguments that come after the command; so all global arguments must come before the command.\n  In the above example this means that  `entrypoint --verbose Command2 string`\n  is valid but `entrypoint Command2 string --verbose` is not.\n",
    "bugtrack_url": null,
    "license": "BSD",
    "summary": "Easily configure a CLI application using a (Pydantic) dataclass.",
    "version": "0.11.0",
    "project_urls": {
        "Repository": "https://github.com/rogiervandergeer/pydargs"
    },
    "split_keywords": [
        "cli",
        " dataclass"
    ],
    "urls": [
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "7e9b25b74f7c6dc9d0f5f413c9031097a106a21207a917c017edc1887a37c33f",
                "md5": "acfdc7ceef427978761b82a00e9da18c",
                "sha256": "b8319117678fabf49c575c5f3d7b759f32d09cff3eb3a0e32eb83a8c539030f0"
            },
            "downloads": -1,
            "filename": "pydargs-0.11.0-py3-none-any.whl",
            "has_sig": false,
            "md5_digest": "acfdc7ceef427978761b82a00e9da18c",
            "packagetype": "bdist_wheel",
            "python_version": "py3",
            "requires_python": ">=3.9",
            "size": 11846,
            "upload_time": "2024-04-04T11:19:43",
            "upload_time_iso_8601": "2024-04-04T11:19:43.509598Z",
            "url": "https://files.pythonhosted.org/packages/7e/9b/25b74f7c6dc9d0f5f413c9031097a106a21207a917c017edc1887a37c33f/pydargs-0.11.0-py3-none-any.whl",
            "yanked": false,
            "yanked_reason": null
        },
        {
            "comment_text": "",
            "digests": {
                "blake2b_256": "a88ff88b092c6876a4437a9366a9954997293ba79a8b1f1c471b3a8e5f6bd361",
                "md5": "a9fae5f133b78fa6ef38eb7621cfe988",
                "sha256": "10e021a4136a3ef0fb6caa2022f63b11c2a8fb6e0c7cec46d9a25897f75c6848"
            },
            "downloads": -1,
            "filename": "pydargs-0.11.0.tar.gz",
            "has_sig": false,
            "md5_digest": "a9fae5f133b78fa6ef38eb7621cfe988",
            "packagetype": "sdist",
            "python_version": "source",
            "requires_python": ">=3.9",
            "size": 24294,
            "upload_time": "2024-04-04T11:19:45",
            "upload_time_iso_8601": "2024-04-04T11:19:45.089311Z",
            "url": "https://files.pythonhosted.org/packages/a8/8f/f88b092c6876a4437a9366a9954997293ba79a8b1f1c471b3a8e5f6bd361/pydargs-0.11.0.tar.gz",
            "yanked": false,
            "yanked_reason": null
        }
    ],
    "upload_time": "2024-04-04 11:19:45",
    "github": true,
    "gitlab": false,
    "bitbucket": false,
    "codeberg": false,
    "github_user": "rogiervandergeer",
    "github_project": "pydargs",
    "travis_ci": false,
    "coveralls": false,
    "github_actions": true,
    "lcname": "pydargs"
}
        
Elapsed time: 0.21494s