Skip to main content

argparcel

image image image Actions status

A minimalist library to parse command-line arguments into a dataclass.

Example usage

# examples/example_0.py
import dataclasses

import argparcel


@dataclasses.dataclass(kw_only=True, frozen=True, slots=True)
class Args:
    a: int
    b: float

    # A `bool` argument will create a linked pair of flags `--c` and `--no-c`.
    c: bool

    # A command line argument will be optional if and only if a default value is
    # provided in the corresponding dataclass field.
    d: str | None = None


if __name__ == "__main__":
    print(argparcel.parse(Args))
$ uv run examples/example_0.py --help
usage: example_0.py [-h] --a A --b B --c | --no-c [--d D]

options:
  -h, --help   show this help message and exit
  --a A
  --b B
  --c, --no-c
  --d D

$ uv run examples/example_0.py --a 2 --b 3.2 --c
Args(a=2, b=3.2, c=True, d=None)

$ uv run examples/example_0.py --a 2 --b 3.2 --no-c
Args(a=2, b=3.2, c=False, d=None)

$ uv run examples/example_0.py --a 2 --b 3.2 --no-c  --d moo
Args(a=2, b=3.2, c=False, d='moo')

We also support:

  • Literal and Enums forcing specific choices
  • conversion to types whose __init__ accepts a string, e.g. pathlib.Path
  • annotated lists, e.g. list[int] or list[pathlib.Path]
  • annotated homogeneous tuples, e.g. tuple[int, int] or tuple[str, ...]
  • 'help' can be provided too
# examples/example_1.py
import dataclasses
import enum
import pathlib
from typing import Literal

import argparcel


class Bird(enum.Enum):
    puffin = enum.auto()
    lark = enum.auto()


@dataclasses.dataclass(kw_only=True, frozen=True, slots=True)
class Args:
    # Using a `Literal` will force a choice between 1, 2, or 3.
    a: Literal[1, 2, 3]

    # An enum will force a choice between the names of the enum elements.
    b: Bird = Bird.puffin

    # A `Path` can be automatically converted from a string. Here we also specify a
    # 'help' message by using a 'docstring' for the field.
    c: pathlib.Path | None = None
    """An important path."""

    # A list will introduce a flag that consumes zero or more elements.
    d: list[float] | None = None

    # A tuple can require exactly a certain number of elements to be specified.
    e: tuple[int, int] | None = None

    # A tuple can also have an unknown number of elements.
    f: tuple[str, ...] | None = None

    # A tuple can also be required to have one or more elements.
    g: tuple[float, *tuple[float, ...]] | None = None


if __name__ == "__main__":
    print(argparcel.parse(Args))
$ uv run examples/example_1.py --help
usage: example_1.py [-h] --a {1,2,3} [--b {puffin,lark}] [--c C] [--d [D ...]] [--e E E]

options:
  -h, --help         show this help message and exit
  --a {1,2,3}
  --b {puffin,lark}
  --c C              An important path.
  --d [D ...]
  --e E E


$ uv run examples/example_1.py --a 2
Args(a=2, b=<Bird.puffin: 1>, c=None, d=None, e=None)

$ uv run examples/example_1.py --a 2 --b lark --c /somewhere/to/go
Args(a=2, b=<Bird.lark: 2>, c=PosixPath('/somewhere/to/go'), d=None, e=None)

$ uv run examples/example_1.py --a 2 --b lark --d 1.0 2.0 3.0
Args(a=2, b=<Bird.lark: 2>, c=None, d=[1.0, 2.0, 3.0])

$ uv run examples/example_1.py --a 2 --e 4 5
Args(a=2, b=<Bird.puffin: 1>, c=None, d=None, e=(4, 5))

Pitfall: forward-references

All types used in annotations must be available at runtime.

Specifically, when you call argparcel.parse(Args), internally it relies upon typings.get_type_hints(Args) working. It will not work if any of the type annotations for fields in Args can't be resolved at runtime.

A plausible scenario for this to fail is when using forward references.

Forward references are used when:

  • annotating with a string, or
  • you have from future import __annotations__ in the module, or
  • you're using Python 3.14 or later.

In any of these cases, a linter rule like ruff's TC003 may encourage you to move an import into a TYPE_CHECKING-guarded block, like so:

from __future__ import annotations

import dataclasses
from typing import TYPE_CHECKING

import argparcel

if TYPE_CHECKING:
    from pathlib import Path


@dataclasses.dataclass
class Args:
    x: Path


argparcel.parse(Args)  # Raises NameError

But if you run this, you'll get:

<...snip stack trace...>
NameError: name 'Path' is not defined

Solutions

If you run into this issue, take your pick from the following solutions:

  1. Suppress your linter to permit the runtime import.
  2. Alternatively, use the argparcel.uses_types decorator when defining the dataclass:
@argparcel.uses_types(Path)
@dataclasses.dataclass
class Args:
    x: Path

This decorator is only a convenience to allow the user to indicate to their linter that the type is required. There's no requirement to specify all types that the dataclass uses.

  1. Use your own contrivance to ensure that the types are referenced at runtime.

Metadata

Release files for argparcel 0.0.9

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for argparcel 0.0.9
File Size Uploaded Provenance Actions
argparcel-0.0.9.tar.gz 8.8 kB Without provenance Details for argparcel-0.0.9.tar.gz

Built distribution (wheel)

Table of built distributions (wheels) for argparcel 0.0.9
File Interpreter ABI Platform Actions
argparcel-0.0.9-py3-none-any.whl Python 3 none any Details for argparcel-0.0.9-py3-none-any.whl

Total release size: 18.0 kB

Release files / argparcel-0.0.9.tar.gz

Download URL argparcel-0.0.9.tar.gz
Size 8.8 kB
Tags Source
SHA-256 checksum
How to use checksums
c60d3b008b25bf0cdaaf405045e53e3c36a1301503914f50ab50464b7a9273d2
BLAKE2b-256 checksum
How to use checksums
e11cb4dcfedd94f036dd792c6fa783b2bb73071d8670f2161c4639543b17ee83
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Release files / argparcel-0.0.9-py3-none-any.whl

Download URL argparcel-0.0.9-py3-none-any.whl
Size 9.2 kB
Tags Python 3
SHA-256 checksum
How to use checksums
271ebe634c997b4dc97692c47e2ac33f8ef98277219414fcb59051f8fca0bd9c
BLAKE2b-256 checksum
How to use checksums
52faf0a08152d3ca947ada22298585a60b655142a83d414de329ed82b3c4a775
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
Yes
Uploaded via uv/0.11.32 {"installer":{"name":"uv","version":"0.11.32","subcommand":["publish"]},"python":null,"implementation":{"name":null,"version":null},"distro":{"name":"Ubuntu","version":"24.04","id":"noble","libc":null},"system":{"name":null,"release":null},"cpu":null,"openssl_version":null,"setuptools_version":null,"rustc_version":null,"ci":true}

Security for argparcel 0.0.9

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page