An extensible configuration object
I've taken to using JSON as a standard format for configuration files, which I find much easier to handle and manage than other formats (especially if the same configuration file is to be parsed by several language runtimes).
A typical configuration of mine looks like this:
{
"stores": {
"#": "Redis store for counters and statistics",
"redis": {
},
"#": "Our primary store",
"postgres": {
"master": "",
"slave": "",
"username": "",
"password": ""
}
},
"services": {
"content": {
"endpoint": "https://foobar",
"wsdl": "foobar.wsdl"
}
},
"#": "Do not add comments inside the logging dictionary - this is handled directly by the logging module",
"logging": {
"version": 1,
"formatters": {
"http": {
"format" : "localhost - - [%(asctime)s] %(process)d %(levelname)s %(message)s",
"datefmt": "%Y/%m/%d %H:%M:%S"
}
},
"handlers": {
"console": {
"class" : "logging.StreamHandler",
"formatter": "http",
"level" : "DEBUG",
"stream" : "ext://sys.stdout"
},
"pygments-xml": {
"class" : "utils.PygmentsHandler",
"formatter": "http",
"level" : "DEBUG",
"stream" : "ext://sys.stdout",
"syntax" : "xml"
},
"ram": {
"class" : "logging.handlers.MemoryHandler",
"formatter": "http",
"level" : "WARNING",
"capacity" : 200
}
},
"loggers": {
"soap.client": {
"level" : "DEBUG",
"handlers": ["pygments-xml"],
"propagate": false
}
},
"root": {
"level" : "INFO",
"handlers": ["ram","console"]
}
}
}
This is all fine and good, since in Python all you need to do is json.load
and get back a dictionary - but it soon becomes unwieldy to access items inside that, so I decided to do it in a nicer way by using attributes:
class Struct(dict):
"""An object that recursively builds itself from a dict and allows easy access to attributes"""
def __init__(self, obj):
dict.__init__(self, obj)
for k, v in obj.items():
if isinstance(v, dict):
self.__dict__[k] = Struct(v)
elif isinstance(v, list):
self.__dict__[k] = [Struct(i) if isinstance(i, dict) or isinstance(i, list) else i for i in v]
else:
self.__dict__[k] = v
def __getattr__(self, attr):
try:
return self.__dict__[attr]
except KeyError:
raise AttributeError(attr)
def __setattr__(self, attr, value):
self.__setitem__(attr,value)
With the above, config = Struct(json.load(...))
gives me a nice object that I can access without hassle by using config.services.content.endpoint
- which is nicer and much more readable than the usual dict notation.
Written by Rui Carmo
Related protips
Have a fresh tip? Share with Coderwall community!
Post
Post a tip
Best
#Python
Authors
Sponsored by #native_company# — Learn More
#native_title#
#native_desc#