Skip to main content

ArgBind

Build CLIs via docstrings and type annotations, with YAML support.

Tests PyPI version Python versions Downloads

Note: This is an extended fork of pseeth/argbind that adds new features — modern type annotations (PEP 585/604), Literal and flexible boolean handling, dataclass default_factory, and YAML $include — published on PyPI as argbind-dbraun. The import name is unchanged (import argbind), so it remains a drop-in replacement (see the CHANGELOG for intentional behavior differences).

ArgBind is a simple way to bind function or class arguments to the command line or to .yml files! It supports scoping of arguments, similar to other frameworks like Hydra and gin-config. ArgBind is very small (only ~800 lines of code, in one file), can be used to make complex and well-documented command line programs, and allows you to configure program execution from .yml files.

If you're migrating from an ArgParse script to an ArgBind script, check out the migration guide. Scroll down to see some examples. Please also look at the current known limitations of ArgBind.

Why ArgBind?

ArgBind was written by Prem Seetharaman to help configure machine learning experiments. ML experiment configuration is often highly nested, and can get out of hand quickly. Rather than switching workflows around too much to accommodate a new framework, the goal was to make already-written scripts easily adaptable, to achieve a few things:

  1. Configure scripts using .yml files. Be able to save .yml files that can be used to rerun scripts the exact same way twice.
  2. Spend time writing actual functions needed to run experiments, not argument parsers.
  3. Be able to run experiment code from other Python scripts, notebooks, or the command line.
  4. Be able to specify arguments from the command line directly to various functions.
  5. Be able to use scoping patterns, so a function can run inside a train scope and test scope, with different results (e.g., for getting a train dataset and a test dataset).

Nothing out there really fit the bill, so Prem wrote ArgBind. If you have an argparse based script, converting it to ArgBind should be very quick! ArgBind is simple, small, and easy to use. To get a feel for how it works, check out usage, design, and examples!

Installation

Install via pip:

python -m pip install argbind-dbraun

Or from source:

git clone https://github.com/DBraun/argbind.git
cd argbind
python -m pip install -e .

This project uses uv. To create a dev environment with the test dependencies and run the suite:

uv sync --extra tests
uv run pytest

Install the pre-commit hooks (ruff format + lint) so they run on every commit:

uvx pre-commit install

Examples

Usage

There are six main functions.

  • bind: Binds keyword arguments (and positional arguments if positional=True) of a function or class to ArgBind.
  • parse_args: Actually parses command line arguments into a dictionary.
  • scope: Context manager that scopes a dictionary containing function arguments to be used by the functions.
  • dump_args: Dumps the args dictionary to a .yml file. Used internally when program is called with --args.save path/to/save.yml.
  • load_args: Loads args from a .yml file. Used internally when program is called with --args.load path/to/load.yml.
  • get_used_args: Gets arguments that have actually been used by call functions up to this point.

Your code with ArgBind generally follows this pattern:

  1. Write a function with a good docstring, and typed arguments. If arguments are not typed, their type will be inferred from the type of the default.
  2. Bind it via bind.
  3. When program is called, parse the arguments via parse_args.
  4. Scope the arguments, and call the bound function within the context block.
  5. Optionally call program with --args.save to save the current execution configuration to a .yml file or --args.load to load arguments from a prior saved execution configuration to run it the same way twice.
  6. Optionally, run your script with --args.debug=1 to see exactly how every bound function is called.

In your program, you can call get_used_args to see which arguments were actually used. Here's a minimal example:

import argbind

@argbind.bind()
def hello(
    name : str = 'world'
):
    """Say hello to someone.

    Parameters
    ----------
    name : str, optional
        Who you're saying hello to, by default 'world'
    """
    print("Hello " + name)

if __name__ == "__main__":
    # Arguments for CLI automatically generated from bound functions under the pattern
    # function_name.function_arg.
    args = argbind.parse_args()
    # When called within a scope, the keyword arguments map to those from CLI or
    # from defaults.
    with argbind.scope(args):
        hello()
    # get_used_args() returns the arguments that were actually used by the bound
    # functions that ran -- here, {'hello.name': 'world'}.
    print(argbind.get_used_args())

Help text is automatically generated from the docstring:

❯ python examples/hello_world/with_argbind.py -h
usage: with_argbind.py [-h] [--args.save ARGS.SAVE] [--args.load ARGS.LOAD] [--args.debug ARGS.DEBUG] [--hello.name HELLO.NAME]

optional arguments:
  -h, --help            show this help message and exit
  --args.save ARGS.SAVE
                        Path to save all arguments used to run script to.
  --args.load ARGS.LOAD
                        Path to load arguments from, stored as a .yml file.
  --args.debug ARGS.DEBUG
                        Print arguments as they are passed to each function.

Generated arguments for function hello:
  Say hello to someone.

  --hello.name HELLO.NAME
                        Who you're saying hello to, by default 'world'

Execution of this could look like:

# Default arguments
❯ python examples/hello_world/with_argbind.py
Hello world
# Binding name from the command line and saving the args.
❯ python examples/hello_world/with_argbind.py --hello.name=you --args.save=/tmp/args.yml
Hello you
# Loading saved arguments.
❯ python examples/hello_world/with_argbind.py --args.load=/tmp/args.yml
Hello you
# Loading saved arguments, and overriding via command line.
❯ python examples/hello_world/with_argbind.py --args.load=/tmp/args.yml --hello.name=me
Hello me
# See how each function is called with args.debug=1.
❯ python examples/hello_world/with_argbind.py --args.load=/tmp/args.yml --args.debug=1
hello(
  name : str = you
)
Hello you

You can also run the hello function from another Python script or a Jupyter notebook:

import argbind
# Import the bound function
from .hello_world import hello
# Load the args
args = argbind.load_args('/tmp/args.yml')
# Scope the args
with argbind.scope(args):
    # Run the bound function
    hello() # Prints 'Hello you'.
hello() # Prints 'Hello world', as it's outside scope.
# Can edit the args before scoping again.
args['hello.name'] = 'me'
with argbind.scope(args):
    hello() # Prints 'Hello me'.

You'll notice that ArgBind forces you to document and type your function arguments, which is always a good idea! Please check out the examples for more details!

Design

ArgBind is designed around a decorator that can be used on functions the user wants to expose to command line or to a .yml file. The arguments to that function are then bound to a dictionary. When the function is called, each argument is looked up in the dictionary and its value is replaced with the corresponding value in the dictionary. The dictionary that the function looks for values in is controlled by scope:

import argbind

@argbind.bind()
def func(arg : str = 'default'):
    print(arg)

dict1 = {
    'func.arg': 1,
}
dict2 = {
    'func.arg': 2
}

with argbind.scope(dict1):
    func() # prints 1
with argbind.scope(dict2):
    func() # prints 2
func(arg=3) # prints 3.

The function arguments are bound to the command line. Continuing the simple program from above:

if __name__ == "__main__":
    args = argbind.parse_args()
    with argbind.scope(args):
        func()
    with argbind.scope(args):
        func(arg=3)

You can call this function like so:

 python examples/readme_example.py --func.arg 5
1 # Looks up `arg` in dict1
2 # Looks up `arg` in dict2
3 # arg is passed in on python call `func(arg=3)`
5 # Looks up `arg` from command line call `--func.arg 5`
3 # arg is passed in from two places: `func(arg=3)` and `--func.arg 5`. Former overrides the latter.

The logic here is that arguments that are bound that are closer to the actual function call get priority. From highest priority, to lowest, it goes:

  1. Bound explicitly in Python code
  2. Bound via command line
  3. Bound via .yml file
  4. Bound via default for kwarg

You can also use bind directly on classes - see here.

Limitations and known issues

There are some limitations to ArgBind, some due to how Python function decorators work, and others out of a desire to keep ArgBind's code simple and straightforward.

Bound function names should be unique

Functions that are bound must be unique, even if they are in different files. The function name is resolved in the argument parser only using the immediate name, not a path to the function etc.

Supported docstring formats

ArgBind uses docstring-parser, and so the only supported styles are: ReST, Google, and Numpydoc-style docstrings.

Not all types are supported

ArgBind supports most types that might pop up in your script, but not all. The supported types can be seen in the typing and modern annotations examples.

Positional arguments should not be saved into .yml files

If a positional argument is saved into a .yml file and loaded via --args.load, then any positional argument passed in the command line will be overridden. Take care not to pass positional arguments via .yml files.

Issues? Questions?

If you've run into some issues with ArgBind, or have some questions, please ask via GitHub Issues. Projects like ArgBind are pretty tricky to get right, so there may be some edge cases that have been missed.

Download files

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

Source Distribution

argbind_dbraun-0.6.0.tar.gz (30.9 kB view details)

Uploaded Source

Built Distribution

If you're not sure about the file name format, learn more about wheel file names.

argbind_dbraun-0.6.0-py3-none-any.whl (15.7 kB view details)

Uploaded Python 3

File details

Details for the file argbind_dbraun-0.6.0.tar.gz.

File metadata

  • Download URL: argbind_dbraun-0.6.0.tar.gz
  • Upload date:
  • Size: 30.9 kB
  • Tags: Source
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for argbind_dbraun-0.6.0.tar.gz
Algorithm Hash digest
SHA256 3723a7770689b3b5ae23fe8bd8496d6335c7f4593fbee1f68ebde7d0a1772e7f
MD5 559d1b88a8abd68b40cce7964fb8af7c
BLAKE2b-256 808af9ee64a3c539bead74b010e31d0eb0e0ccf24c2dfcb9ac0d3dfb90c96f9d

See more details on using hashes here.

Provenance

The following attestation bundles were made for argbind_dbraun-0.6.0.tar.gz:

Publisher: publish.yml on DBraun/argbind

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

File details

Details for the file argbind_dbraun-0.6.0-py3-none-any.whl.

File metadata

  • Download URL: argbind_dbraun-0.6.0-py3-none-any.whl
  • Upload date:
  • Size: 15.7 kB
  • Tags: Python 3
  • Uploaded using Trusted Publishing? Yes
  • Uploaded via: twine/6.1.0 CPython/3.13.12

File hashes

Hashes for argbind_dbraun-0.6.0-py3-none-any.whl
Algorithm Hash digest
SHA256 d115f53babc93188626f13c480e47d0d0188bff32923990e8810409e3bba577b
MD5 c5aa0c3a430ec6617591c5ac4945ccbb
BLAKE2b-256 08dbb7c2d7599dc64c660af6721a0ce61999d96dce4d3d400c48f55fc6e5a3a3

See more details on using hashes here.

Provenance

The following attestation bundles were made for argbind_dbraun-0.6.0-py3-none-any.whl:

Publisher: publish.yml on DBraun/argbind

Attestations: Values shown here reflect the state when the release was signed and may no longer be current.

Release history Release notifications | RSS feed

This release

0.6.0 This release

2 files

0.5.2

2 files

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