The ChainMap use case

The use case for chaining maps together fits nicely with Python's concept of local versus global definitions. When we use a variable in Python, first the local namespaces and then the global namespaces are searched, in that order. In addition to searching both namespaces for a variable, setting a variable is done in the local namespace without disturbing the global namespace. This default behavior (without the global or nonlocal statements) is also how ChainMap works.

When our applications start running, we often have properties that come from command-line parameters, configuration files, OS environment variables, and possibly a default file of settings installed with the software. These have a clear precedence order where a value supplied on the command-line is most important, and an installation-wide default setting is the least important. Because a ChainMap object will search through the various mappings in order, it lets us merge many sources of parameters into a single dictionary-like structure, so that we can easily locate a setting. 

We might have an application startup that combines several sources of configuration options like this:

import argparse
import json
import os
import sys
from collections import ChainMap
from typing import Dict, Any

def
get_options(argv: List[str] = sys.argv[1:]) -> ChainMap:
parser = argparse.ArgumentParser(
description="Process some integers.")
parser.add_argument(
"-c", "--configuration", type=open, nargs="?")
parser.add_argument(
"-p", "--playerclass", type=str, nargs="?",
default="Simple")
cmdline = parser.parse_args(argv)

if cmdline.configuration:
config_file = json.load(cmdline.configuration)
cmdline.configuration.close()
else:
config_file = {}

default_path = (
Path.cwd() / "Chapter_7" / "ch07_defaults.json")
with default_path.open() as default_file:
defaults = json.load(default_file)

combined = ChainMap(
vars(cmdline), config_file, os.environ, defaults)
return combined

The preceding code shows us the configuration from several sources, such as the following:

  • The command-line arguments. In this example, there is only one argument, called playerclass, but a practical application will often have many, many more.
  • One of the arguments, configuration, is the name of a configuration file with additional parameters. This is expected to be in the JSON format, and the file's contents are read.
  • Additionally, there's a defaults.json file with yet another place to look for the configuration values.

From the preceding sources, we can build a single ChainMap object. This object permits looking for a parameter in each of the listed locations in the specified order. The ChainMap instance use case will search through each mapping from highest precedence to lowest, looking for the given key and returning the value. This gives us a tidy, easy-to-use source for runtime options and parameters.

We'll look at this again in Chapter 14, Configuration Files and Persistence, and Chapter 18, Coping with the Command Line.

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

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