Quick start

An option hierarchy is build by subclassing inept.Config and using the with statement. Inside of the class body, the special variable _ is made avalaible and provides different context managers that can customize the option nesting:

  • a with _.options block will list optional values

  • a with _.group block will list mandatory values

  • a with _.switch block will list mutually exclusive values

[1]:
import inept

class RestaurantMenu(inept.Config):
    with _.options:
        coffe: bool = False
        drink: str
        with _.switch:
            with _.group as simple_menu:
                dish: str = "steak and fries"
                with _.switch:
                    starter: str
                    dessert: str = "apple pie"
            with _.group as full_menu:
                starter: str = "salad"
                dish: str = "lasagna"
                dessert: str = "compote"

An instance of this class will store option values while ensuring consistency with the declared hierachy. Each option has a unique key, a string made of the nested option names, assembled with '.'.

[2]:
order = RestaurantMenu()
order.all_keys()
[2]:
['coffe',
 'drink',
 'simple_menu',
 'simple_menu.dish',
 'simple_menu.starter',
 'simple_menu.dessert',
 'full_menu',
 'full_menu.starter',
 'full_menu.dish',
 'full_menu.dessert']

A configuration object acts like a dict for the set and get operations.

[3]:
order['coffe'] = True
order['full_menu.dessert'] = "creme brulee"
order['full_menu.starter']  # default values are automatically set
[3]:
'salad'

The method to_dict() provides the full state of the configuration.

[4]:
order.to_dict()
[4]:
{'coffe': True,
 'full_menu.starter': 'salad',
 'full_menu.dish': 'lasagna',
 'full_menu.dessert': 'creme brulee'}

According to the options/group/switch used during declaration, the options are optional, mandatory or mutually exclusive. The configuration object ensures the consistency of its own state.

[5]:
order['simple_menu'] = True  # this erases 'full_menu' because 'simple_menu' and 'full_menu' are in a switch block
order.to_dict()
INFO: 'full_menu' is owerwritten by 'simple_menu'
[5]:
{'coffe': True,
 'simple_menu.dish': 'steak and fries',
 'simple_menu.dessert': 'apple pie'}

A nested dict can also be produced.

[6]:
order.to_nested_dict()
[6]:
{'coffe': True,
 'simple_menu': {'dish': 'steak and fries', 'dessert': 'apple pie'}}

A configuration can be filled from a dict.

[7]:
new_order = RestaurantMenu()
some_dict = {'full_menu': True, 'drink': 'water'}
some_nested_dict = {'simple_menu': {'starter': 'salad'}}
new_order.update(some_dict)
new_order.to_dict()
[7]:
{'coffe': False,
 'drink': 'water',
 'full_menu.starter': 'salad',
 'full_menu.dish': 'lasagna',
 'full_menu.dessert': 'compote'}
[8]:
new_order.update(inept.flatten(some_nested_dict))
new_order.to_dict()
INFO: 'full_menu' is owerwritten by 'simple_menu'
INFO: 'dessert' is owerwritten by 'starter'
[8]:
{'coffe': False,
 'drink': 'water',
 'simple_menu.dish': 'steak and fries',
 'simple_menu.starter': 'salad'}

The command line arguments can be loaded at any time with

[ ]:
# $ python myscript.py --coffe true --full_menu.dessert jelly
order.load_cli()