Skip to main content

Pydargs allows configuring a dataclass through command line arguments.

Project description

pydargs

Pydargs allows configuring a (Pydantic) dataclass through command line arguments.

Installation

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

pip install pydargs

Usage

A minimal usage example would be:

from dataclasses import dataclass
from pydargs import parse


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

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

After which this entrypoint can be called with

entrypoint --number 42

or

entrypoint --number 42 --some-string abcd

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:

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.

Supported Field Types

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

  • Enums or literals comprised of those types.
  • 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.

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.

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:

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:

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,

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:

@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.

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,

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:

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.

For example, with the following dataclass,

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:

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:

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 somthing like:

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.

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

pydargs-0.8.0.tar.gz (17.4 kB view details)

Uploaded Source

Built Distribution

pydargs-0.8.0-py3-none-any.whl (8.5 kB view details)

Uploaded Python 3

File details

Details for the file pydargs-0.8.0.tar.gz.

File metadata

  • Download URL: pydargs-0.8.0.tar.gz
  • Upload date:
  • Size: 17.4 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.7

File hashes

Hashes for pydargs-0.8.0.tar.gz
Algorithm Hash digest
SHA256 60abec1a8b918e6c44649f54898da8b65076cebbaba8c5edd50d534f7fde10ed
MD5 ad9e20bb9c1c5c25215eaa88a9ea1799
BLAKE2b-256 e8d921068f798f1bdd1c02e57c47bddda50277514cf5da76b50b65d4463f44a5

See more details on using hashes here.

Provenance

File details

Details for the file pydargs-0.8.0-py3-none-any.whl.

File metadata

  • Download URL: pydargs-0.8.0-py3-none-any.whl
  • Upload date:
  • Size: 8.5 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? No
  • Uploaded via: twine/4.0.2 CPython/3.11.7

File hashes

Hashes for pydargs-0.8.0-py3-none-any.whl
Algorithm Hash digest
SHA256 4a21bddf6974b8622db24efa598f90330df3c1d5726e6e4be9cdf324ba410ea8
MD5 ba638a4daa5051e075844f2a095a0dc6
BLAKE2b-256 59e1d4d990b08600921e4e48f7dc056e8223c5bf3d506a8df5c6d2514271e754

See more details on using hashes here.

Provenance

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page