1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177
|
#!/usr/bin/python
"""Example of reading application settings from a configuration file"""
from application.configuration import *
from application.process import process
from application.system import default_host_ip
from application import log
# Define a specific data type we will later use with the configuration
class Priority(int):
"""A numeric priority level. The keywords High, Normal and Low map to certain numeric values."""
def __new__(typ, value):
if isinstance(value, (int, long)):
return int(value)
elif isinstance(value, basestring):
map = {'high': 10, 'normal': 50, 'low': 100}
try:
return map.get(value.lower()) or int(value)
except ValueError:
raise ValueError, "invalid priority value: should be a number or the keywords High, Normal or Low"
else:
raise TypeError, 'value should be an integer or string'
# Define a class that gives access (through its attributes) to the values
# defined in a section (or possibly more) of the configuration file.
# The data type for an attributes is taken from the type of the specified
# default value, or it can be declared using a ConfigSetting descriptor in
# case the type used to instantiate the attribute is just a validator.
#
# The python bool type is automatically mapped to the datatypes.Boolean
# validator which recognizes multiple logic values like: yes/no, on/off,
# true/false, 1/0, so there is no need to use a ConfigSetting descriptor
# for a boolean value, only to assign a True/False value to its attribute.
class NetworkConfig(ConfigSection):
name = 'undefined'
ip = ConfigSetting(type=datatypes.IPAddress, value=default_host_ip)
port = 8000
priority = ConfigSetting(type=Priority, value=Priority('Normal'))
domains = ConfigSetting(type=datatypes.StringList, value=[])
allow = ConfigSetting(type=datatypes.NetworkRangeList, value=[])
use_tls = False
# And another class for another section
class StorageConfig(ConfigSection):
dburi = 'mysql://undefined@localhost/database'
# Dump the default hardcoded values of the options defined above
print "Settings before reading the configuration file (default hardcoded values)\n"
print NetworkConfig
print
print StorageConfig
print
# Read the settings from the configuration file into the attributes of our
# configuration classes. The read function takes a configuration file name
# and a section name (or an iterable that returns multiple section names
# in which case they will be read in the order that the iterable returns
# them). Internally the ConfigSection will create a ConfigFile instance
# using the provided filename. The file is searched in both the system
# and the local config directories and the files which are present will be
# loaded in this order. This means that a local config file will overwrite
# settings from the system config file if both are present.
# The config directories are configurable on the process instance available
# from application.process.process, as process.system_config_directory and
# process.local_config_directory. By default the system config directory
# defaults to /etc and the local config directory defaults to the path from
# where the script is run, thus allowing applications to run from inside a
# directory without any other dependencies. In this example the config file
# will be read from ./config.ini which is in the local config directory.
#
# While reading the section, only settings that are defined on the config
# class wil be considered. Those present in the section that do not have a
# correspondent in the class attributes will be ignored, while the class
# attributes for which there are no settings in the section will remain
# unchanged.
#
NetworkConfig.read('config.ini', 'Network')
StorageConfig.read('config.ini', 'Storage')
# Dump the values of the options after they were loaded from the config file
print "\nSettings after reading the configuration file(s)\n"
print NetworkConfig
print
print StorageConfig
print
# Configuration options can be accessed as class attributes
ip = NetworkConfig.ip
# Starting with version 1.1.2, there is a simpler way to have a section loaded
# automatically, by defining the __cfgfile__ and __section__ attributes on
# the class. (Note: between version 1.1.2 through 1.1.4, __cfgfile__ was
# named __configfile__)
# Here is an example of such a class that will be automatically loaded
print "\n------------------------------------\n"
print "Using __cfgfile__ and __section__ to automatically load sections\n"
class AutoStorageConfig(ConfigSection):
__cfgfile__ = 'config.ini'
__section__ = 'Storage'
dburi = 'mysql://undefined@localhost/database'
# Dump the values of the options after they were loaded from the config file
print "Settings in the automatically loaded section\n"
print AutoStorageConfig
# An example of how to use tracing to see inner workings of our configuration
# class and to display its internal state after it is operated on. We will
# redefine the NetworkConfig class with autoloading and tracing enabled
#
print "\n------------------------------------\n"
print "Tracing the inner working of a config class using __tracing__\n"
class NetworkConfigTraced(ConfigSection):
__cfgfile__ = 'config.ini'
__section__ = 'Network'
__tracing__ = log.level.INFO # log trace to INFO level
name = 'undefined'
ip = ConfigSetting(type=datatypes.IPAddress, value=default_host_ip)
port = 8000
priority = ConfigSetting(type=Priority, value=Priority('Normal'))
domains = ConfigSetting(type=datatypes.StringList, value=[])
allow = ConfigSetting(type=datatypes.NetworkRangeList, value=[])
use_tls = False
print "\nReset to defaults and read settings from config file again\n"
# reset to defaults
NetworkConfigTraced.reset()
# read back from config file. since we defined __cfgfile__ and __section__
# we do not need to pass a file and section as arguments to read, the above
# mentioned class atributes will be used instead. Passing arguments to read()
# will overwrite the class attributes though.
NetworkConfigTraced.read()
print "\nChange individual options\n"
NetworkConfigTraced.name = 'manually_set_name'
NetworkConfigTraced.ip = '1.2.3.4'
print "\nSave current state, reset to defaults and then restore from saved state\n"
# save a snapshot of the current settings
state = dict(NetworkConfigTraced)
# reset to defaults
NetworkConfigTraced.reset()
# restore to a previously saved state
NetworkConfigTraced.set(**state)
# disabled tracing
NetworkConfigTraced.__tracing__ = None
# the following operations will not be traced
NetworkConfigTraced.reset()
NetworkConfigTraced.read()
NetworkConfigTraced.set(**state)
# We can also get individual settings from a given section.
#
# For this we create ConfigFile instance that will handle the configuration
# file. The information about the system and local configuration directories
# and where are the configuration files being looked up (which was presented
# above with the ConfigSection.read() method) apply here as well.
#
print "\n------------------------------------\n"
print "Reading individual settings from sections without using ConfigSection"
configuration = ConfigFile('config.ini')
dburi = configuration.get_setting('Storage', 'dburi', type=str, default='undefined')
print "\nGot dburi directly from Storage section as `%s'\n" % dburi
|