simple-parsing: typed dataclass arguments on top of argparse
Simple, Elegant, Typed Argument Parsing with argparse
At a glance
- What is it?
- simple-parsing does not replace argparse, it decorates it. You describe your command line options as dataclasses, hand the class to the parser, and get back a typed object, help strings generated from the comments in your own source, nested option groups, prefixes so one class can be reused twice, and defaults read from JSON or YAML files.
- Who is it for?
- simple-parsing suits a project whose command line interface has grown past a dozen arguments, where the same block of options appears in more than one place, or where the options are already shaped like dataclasses and the parser is the only thing that has not caught up.
- Can I use it commercially?
- Yes. MIT is a permissive licence: you can use, modify and sell software built on it, as long as you keep its copyright and licence notices.
- Is it still maintained?
- Yes. The repository last received commits 68 days ago.
- What is it written in?
- Mainly Python, according to GitHub's language statistics.
Answers come from the project's GitHub data, last synced on October 22, 2026, and from our analysis. They are not legal advice.
Editorial analysis
A layer on argparse, not a replacement for it
simple-parsing allows you to transform your ugly argparse scripts into beautifully structured, strongly typed little works of art, and the README immediately puts a limit on what that means: this isn't a fancy, complicated new command-line tool either, this simply adds new features to plain-old argparse.
That framing matters, because the most common objection to a dataclass based argument library is that it becomes a second argument parser with its own conventions, its own error messages and its own quirks. Here the underlying argparse is still there. The parser class comes from simple_parsing, the options are registered with add_argument as usual, and the new part is add_arguments, which takes a dataclass and turns its fields into arguments.
The second claim in the README is about reuse. Using dataclasses, simple-parsing makes it easier to share and reuse command-line arguments, no more copy-pasting. That is the real motivation, and it shows up in the feature list as modular, reusable, cleanly grouped arguments.
The supported feature set is inheritance, nesting, easy serialization to json/yaml, automatic help strings from comments, and much more. The dependency list is small enough to explain why it works that way: docstring-parser, which reads the comments and docstrings to build the help text, and typing-extensions. The package requires Python 3.9 or newer, is MIT licensed, and is published on PyPI as simple-parsing.
The project is by Fabrice Normandin. The recent releases are v0.1.7 in January 2025, which reduced logging, moved to Poetry and added a config path argument, v0.1.8 in January 2026, which switched to UV, fixed bugs and added add_help in parse, and v0.1.9 in July 2026. The last push to the repository was on 2026-08-16.
Defining options as a dataclass, and where the help text comes from
The core call is parser.add_arguments(Options, dest="options"), and the demo in the README shows the whole shape of it.
A dataclass named Options holds the fields, with a docstring that becomes the group title in the help output, and the comment beside each field becomes that argument's help text. A field without a default is a required argument; a field with a default is optional, and the type annotation gives the type.
So log_dir: str with a comment is a required string argument, and learning_rate: float = 1e-4 with a comment is an optional float defaulting to 0.0001.
That last point is the one that changes how you write the script. The help text and the type and the default and the required-ness all come from one place, the dataclass, rather than from four separate places in an add_argument call. The README's argument for this is practical rather than aesthetic: a user-friendly help message is often hard to write and to maintain, especially as the number of arguments increases, and with simple-parsing your arguments and their descriptions are defined in the same place.
The result of parsing is a typed object. The demo prints options: Options(log_dir='logs', learning_rate=0.0001), which is the dataclass repr, not a namespace of loose values. So a function can take Options rather than three untyped strings, and the type checker can see it.
Note that this does not remove the need for plain arguments. The demo registers --foo with an ordinary add_argument call and prints args.foo separately, because some options do not belong to a dataclass. The library adds to argparse rather than replacing it, which means you can mix the two freely.
The one line path for a script with one dataclass
Not every script needs a parser object, and the README has a separate section for the simplified API, marked as new.
For a simple use case, where you only want to parse a single dataclass, you can use the simple_parsing.parse or simple_parsing.parse_known_args functions:
options: Options = simple_parsing.parse(Options)
# or:
options, leftover_args = simple_parsing.parse_known_args(Options)The first returns the dataclass instance directly, so the script has a typed object as its only argument handling. The second returns the instance and the leftover arguments, which is the behaviour of the argparse function of the same name: arguments that were not recognised are handed back rather than causing a parse error.
That second form is the one to reach for when the script is a library entry point that other tools will call with their own flags. A training script invoked by an experiment runner, for example, will receive arguments the runner wants to pass through, and parse_known_args lets the script keep its own options while letting the rest through.
The release notes for v0.1.8 mention add_help in parse, which is the detail to know about here: the simplified entry point gained a way to control whether the help flag is added. For a program that is not the main entry point of the command line, the auto-generated help option is noise, and being able to turn it off keeps the generated usage message honest about what the program actually accepts.
So the API has two levels, and the choice between them is about how much of the parser you want to own.
Prefixing, subgroups and the end of copy-paste
The reuse feature is the one that justifies the library, and it has two mechanisms.
The first is prefixes. When you need to add a new group of command-line arguments similar to an existing one, instead of copy-pasting a block of argparse code and renaming variables, you can reuse your argument class and let the ArgumentParser take care of adding relevant prefixes to the arguments for you.
parser.add_arguments(Options, dest="train")
parser.add_arguments(Options, dest="valid")
args = parser.parse_args()
train_options: Options = args.train
valid_options: Options = args.validThe same class is registered twice under two destinations, and the arguments become --train.log_dir and --valid.log_dir, which is the form the README's console example shows. The prefixes can also be set explicitly, or not be used at all, and the Prefixing Guide covers the options.
The second is subgroups, with the subgroups function, and it answers a different question. Where prefixing lets the same class appear more than once, subgroups let you choose between different argument groups, which is what you want when a script has modes and each mode has its own options.
Together these two cover the common cases in real scripts. A training script with train and validation options, a script with a debug mode and a normal mode, an evaluation script that shares the model configuration with the training script.
The thing to be careful about is the coupling. The dataclass is now the schema for the command line, so two groups that share a class also share their field names, their types and their defaults. That is the point when the groups are genuinely the same shape, and a limitation when they are not.
Config files, serialization, inheritance and nesting
The rest of the feature list covers the cases where the command line is not the only source of configuration.
Default values for command-line arguments can easily be read from many different formats, including json and yaml. So a script can ship a configuration file with the defaults, and the command line can override individual values on top of it.
Easy serialization covers the other direction: saving and loading configs to json or yaml. That is what makes the combination useful rather than merely convenient. If a run's configuration can be written out as JSON, then the exact arguments a run used can be stored with the results, and a later run can be reproduced from that file. The yaml support is an optional extra rather than a required dependency, so a script that does not need it does not pay for it.
Inheritance lets you customize an existing argument class by extending it and adding your own attributes, which the README connects to code reuse across projects. A class holding the common options can be inherited by a class holding the options for one tool, and the subclass adds what is specific to it.
Nesting allows dataclasses within dataclasses, as deep as you need. A nested dataclass becomes a group of arguments, which is how you get a structured command line rather than a flat list of forty options.
Then there are the parsing details that plain argparse makes awkward. Lists and tuples are handled through the builtin type annotations, so the library automatically converts values to the right type and can parse nested lists or tuples, which the README calls sometimes tricky to do with regular argparse. Enums are supported as well, so a choice argument can be a Python enum rather than a string that the code then has to validate.
The examples directory follows the same structure as the feature list, with one directory per feature: config_files, container_types, custom_args, dataclasses, docstrings, enums, inheritance, merging, nesting, partials, prefixing, serialization, simple, subgroups, subparsers and ugly.
A small dependency footprint and a serious test setup
The project metadata says a lot about how the library is meant to be used.
The runtime dependencies are two: docstring-parser, pinned to a compatible release of the 0.15 series, and typing-extensions at 4.5.0 or newer. The optional extras are yaml, which brings pyyaml, and toml, which brings tomli and tomli-w for reading and writing. So the library does not force a YAML parser on a script that only uses JSON, and TOML support is there for people who want it.
The build system is hatchling with uv-dynamic-versioning, which is why the version is dynamic in the project table, and the repository carries a uv.lock. The move from Poetry to UV is visible in the v0.1.8 release title, so the packaging story here has already changed once.
The linting and formatting configuration is brief: ruff with a line length of 99 and a rule selection of E4, E7, E9, I and UP, which is the import sorting and the pyupgrade rules, docformatter wrapping summaries and descriptions at 99, and codespell with the logs and data directories skipped.
The pytest configuration is the interesting part. The addopts include --doctest-modules and --benchmark-autosave, and the test paths are the test directory and the simple_parsing package itself. Running the doctests of the library's own modules means the examples in the docstrings are executed rather than merely read. The norecursedirs setting excludes the examples and docs directories, which is sensible since the examples are demonstration programs rather than tests. The dev dependency group adds pytest-benchmark, pytest-regressions for output comparison, pytest-xdist for parallel runs, plus numpy and matplotlib for the examples that need them.
So the test suite runs the library's documentation as tests, which is the same philosophy as the help strings coming from the source comments.
Editorial conclusion
simple-parsing suits a project whose command line interface has grown past a dozen arguments, where the same block of options appears in more than one place, or where the options are already shaped like dataclasses and the parser is the only thing that has not caught up. It does not suit a script with three arguments, and it does not suit a team that wants its CLI schema independent of its data classes, because here the dataclass is the schema and the help text lives in the comments beside the fields. Check three things before you adopt it: whether your option groups map cleanly onto dataclasses, whether your Python version is 3.9 or newer, and how the config file feature should interact with the command line when both set the same value. The last push to the repository was on 2026-08-16 and the newest release is v0.1.9.
Frequently asked questions
What does simple-parsing add to argparse?
It lets you define command line options as dataclasses and register them with parser.add_arguments, so you get typed objects instead of loose namespace values, help strings generated from the comments beside your fields, and the ability to reuse the same option class more than once with prefixes.
How do I install simple-parsing and parse a single dataclass?
Install it with pip install simple-parsing, which needs Python 3.9 or newer. For a script with one dataclass you can use simple_parsing.parse(Options) to get the instance directly, or simple_parsing.parse_known_args(Options) to get the instance and the arguments it did not recognise.
How do I use the same argument group twice with simple-parsing?
Register the class more than once with different destinations, for example parser.add_arguments(Options, dest="train") and parser.add_arguments(Options, dest="valid"), and the parser adds the prefixes so the arguments become --train.log_dir and --valid.log_dir. The Prefixing Guide covers setting the prefixes explicitly or leaving them off.
Can simple-parsing read defaults from a config file?
Yes. Default values for command line arguments can be read from many formats including json and yaml, and the same values can be serialized back out to json or yaml. The yaml support is an optional extra so it does not become a mandatory dependency.
Where do the help strings in simple-parsing come from?
From the docstring of the dataclass, which becomes the group title, and from the comment written beside each field, which becomes that argument's help text. The docstring-parser dependency does the reading, so the descriptions live in the same place as the options.
Official sources
Add this badge to your README
If you maintain this project, the badge below links readers to this analysis and shows its maintenance status from the daily GitHub snapshot. Paste the markdown into your README; add ?metric=license or ?metric=stars to the image URL for a different field.
[](https://hysenlabs.com/projects/lebrice-simpleparsing)Was this useful?