Storing the configuration in JSON or YAML files

We can store configuration values in JSON or YAML files with relative ease. The syntax is designed to be user-friendly. While we can represent a wide variety of things in YAML, we're somewhat restricted to representing a narrower variety of object classes in JSON. We can use a JSON configuration file that is similar to the following code:

{ 
    "table":{ 
        "dealer":"Hit17", 
        "split":"NoResplitAces", 
        "decks":6, 
        "limit":50, 
        "payout":[3,2] 
    }, 
    "player":{ 
        "play":"SomeStrategy", 
        "betting":"Flat", 
        "rounds":100, 
        "stake":50 
    }, 
    "simulator":{ 
        "samples":100, 
        "outputfile":"p2_c13_simulation.dat" 
    } 
} 

The JSON document looks like a dictionary of dictionaries; this is precisely the same object that will be built when we load this file. We can load a single configuration file using the following code:

import json 
config = json.load("config.json") 

This allows us to use config['table']['dealer'] to look up the specific class to be used for the dealer's rules. We can use config['player']['betting'] to locate the player's particular betting strategy class name.

Unlike INI files, we can easily encode tuple like a sequence of values. So, the config['table']['payout'] value will be a proper two-element sequence. It won't, strictly speaking, be tuple, but it will be close enough for us to use it without having to use ast.literal_eval().

Here's how we'd use this nested structure. We'll only show you the first part of the main_nested_dict() function:

def main_nested_dict(config: Dict[str, Any]) -> None:
dealer_nm = config.get("table", {}).get("dealer", "Hit17")
dealer_rule = {
"Hit17": Hit17(),
"Stand17": Stand17()
}.get(dealer_nm, Hit17())
split_nm = config.get("table", {}).get("split", "ReSplit")
split_rule = {
"ReSplit": ReSplit(),
"NoReSplit": NoReSplit(),
"NoReSplitAces": NoReSplitAces()
}.get(split_nm, ReSplit())
decks = config.get("table", {}).get("decks", 6)
limit = config.get("table", {}).get("limit", 100)
payout = config.get("table", {}).get("payout", (3, 2))
table = Table(
decks=decks, limit=limit, dealer=dealer_rule, split=split_rule, payout=payout
)

This is very similar to the main_ini() function mentioned previously. When we compare this with the preceding version, using configparser, it's clear that the complexity is almost the same. The naming is slightly simpler, that is, we use config.get('table',{}).get('decks') instead of config.getint('table','decks').

The main difference is shown in the highlighted line. JSON format provides us with properly decoded integer values and proper sequences of values. We don't need to use eval() or ast.literal_eval() to decode the tuple. The other parts, to build Player and configure the Simulate object, are similar to the main_ini() version.

In some cases, the nested structure of a JSON file can be confusing to edit. One way to simplify the syntax is to use a slightly different approach to organizing the data. In the next section, we'll explore a way to remove some of the complexity by using a flatter structure.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset