Here's a unique Python hack (that might be a bad idea.)
#!/usr/bin/env python3 # -*- coding: utf-8 -*- """ Created on 2024-04-11T18:32:02-04:00 @author: nate """ import argparse import ast import os basedir = os.path.dirname(__file__) class PyLiteralAction(argparse.Action): ''' Parse 0 or more Python literals as Python objects. Example: parser = argparse.ArgumentParser(description="Argparse demo") parser.add_argument('--test-arg', action=PyLiteralAction, help="A test action") args = parser.parse_args() ''' def __init__(self, option_strings, dest, default=None, required=True, help=None): super().__init__(option_strings=option_strings, dest=dest, nargs="*", required=required, help=help) def __call__(self, parser, namespace, values, option_string=None): parsed_obj = True if len(values) == 0: setattr(namespace, self.dest, None) return values = ",".join(values) parsed_obj = ast.literal_eval(values) setattr(namespace, self.dest, parsed_obj) parser = argparse.ArgumentParser(description="Argparse demo") parser.add_argument('--test-arg', action=PyLiteralAction, help="A test action") args = parser.parse_args() obj_type = type(args.test_arg) print(f"{obj_type}: {args.test_arg}")
The idea here is to make use of Python's built-in ast
module to
parse command line arguments as "simple" Python objects.
1. Example
Let us take this opportunity to interactively explore the properties of this argparse action. For one, it's required; failing to include it produces an error:
./literal_action.py
usage: literal_action.py [-h] --arg1 [ARG1 ...] literal_action.py: error: the following arguments are required: --arg1
If we include --arg1
but do not provide any value,
./literal_action.py
usage: literal_action.py [-h] --arg1 [ARG1 ...] literal_action.py: error: the following arguments are required: --arg1
We can use this to pass simple Python literals such as integers:
./literal_action.py --arg1=44444
44444 (type: <class 'int'>)
Or a tuple of literals,
./literal_action.py --arg1="(1, 2, 3, '4')"
(1, 2, 3, '4') (type: <class 'tuple'>)
Or a dictionary of literals,
./literal_action.py --arg1 "{1: 'A', 2: 'B'}"
{1: 'A', 2: 'B'} (type: <class 'dict'>)
Another interesting property is that multiple arguments separated by a space are parsed into a tuple.
./literal_action.py --arg1 1 2 3
(1, 2, 3) (type: <class 'tuple'>)
It can also parse complicated tuples of literals like this one:
./literal_action.py --arg1 "{1: 'A', 2: 'B'}" 123 456
({1: 'A', 2: 'B'}, 123, 456) (type: <class 'tuple'>)