#!/usr/bin/env python3 # :Copyright: © 2022 Günter Milde. # :License: Released under the terms of the `2-Clause BSD license`_, in short: # # Copying and distribution of this file, with or without modification, # are permitted in any medium without royalty provided the copyright # notice and this notice are preserved. # This file is offered as-is, without any warranty. # # .. _2-Clause BSD license: https://opensource.org/licenses/BSD-2-Clause # :Id: $Id: argument_spec.py 9002 2022-02-08 14:15:00Z milde $ """Proof of concept for a new data structure for Settings Specifications. See dep-999-settings_spec.txt for the rationale. Uncomplete. """ import argparse import dataclasses from typing import Any, Callable, Union from collections.abc import Sequence @dataclasses.dataclass class Setting: """Store specification of a setting / command-line argument. Data fields resemble the `argparer.add_argument()` methods parameters. Differences: - Only the first positional argument is an "argument string" (positional argument or long option). - Additional fields: `short_option`, """ arg_string: str """Exactly one argument string, e.g. "--foo" or "source". Use the 'short_option' key for additional short option strings. """ help: str = '' """A brief description of what the argument does.""" action: Union[str, argparse.Action] = None """The basic type of action to be taken when this argument is encountered at the command line. Standard actions: * store, store_const, store_true, store_false * append, append_const, count, """ choices: Sequence = None """A container of the allowable values for the setting.""" const: Any = None """A constant value required by some action and nargs selections.""" default: Any = None """The value produced if the setting is not specified or None.""" dest: str = None """The name of the setting. Default derived from `arg_string`. """ metavar: str = None """A name for the setting in usage messages.""" nargs: int = None """The number of command-line arguments that should be consumed.""" type: Callable = None """The type to which the command-line should be converted. A callable accepting a single string and returning the value after conversion to the expected data type and eventually validation. `ValueError` and `TypeError` are caught. """ short_option: str = None """Short command line option string (only for "generic" settings). Short options are reserved for common settings, components are restricted to using long options. """ @dataclasses.dataclass class SettingsGroup: """Runtime settings and command-line options of an argument group.""" title: str = None """Option group title The default (None) implies no group, just a list of single options. """ description: str = None """Description of the argument group. Printed with --help""" arguments: Sequence = () """A sequence of `Setting` instances specifying the arguments.""" def parse_arguments_spec(specs): """Return a dict of Settings instances for active runtime settings""" active_settings = {} for settings_group in specs: for argument in settings_group.arguments: destination = (argument.dest or argument.arg_string.strip('-').replace('-', '_')) active_settings[destination] = argument return active_settings # Example: arguments_spec = ( # tuple of groups SettingsGroup( title = 'General Docutils Settings', description = 'was gutes', arguments = ( Setting('--title', 'Title document metadata entry.'), Setting('--strict-visitor', help = None, action = 'store_true'), Setting('--generator', short_option = '-g', help = 'Include a "Generated by Docutils" credit ' 'and link.', action = argparse.BooleanOptionalAction), ) # close argument descriptions ), # close group ) active_settings = parse_arguments_spec(arguments_spec) for k, v in active_settings.items(): print(f'{k}: {v}')