Converters are deceptively simple.
You may know that JSON plays well with a limited set of value types. ConfigViper just provides a way to work easily with Python dictionaries. For persistence, ConfigViper stores your configuration values to a file in JSON format. Why JSON? Because JSON is a portable format, it is human readable and can be easily edited with any text editor.
So you’ll need converters if you want to store more sofisticated Python types, like dates, times, decimal values (not only floats), or whatever type you can convert from Python to a type JSON can handle. A converter is a simple Python class with two methods: to_python and to_json. Convertes works on a per config-path basis. This means that you can have a specialized converter for a complex type for an specific config-path.
ConfigViper comes with built-in converters for date (DateConverter), time (TimeConverter), datetime (DatetimeConverter) and decimal (DecimalConverter) objects. You can refer to API Documentation for details on these converters. The converters module also offers instances of these built-in converters as DATE_CONVERTER, DATETIME_CONVERTER, DECIMAL_CONVERTER, and TIME_CONVERTER constants.
Any class should act as a converter. It just needs to provide two methods, one called to_python and another called to_json. By the way, a converter can inherit from Converter, but it’s not a requirement and your class will not gain anything by doing this (as I said, converters are deceptively simple).
The to_json method should convert your Python type to a type JSON can handle. You can serialize your Python type to a string, for example, or you can return a dictionary with types JSON can handle. The to_python method should convert your JSON value back to your Python type. Let’s build a converter for a Person class:
class Person(object):
name = ''
age = 0
def __init__(self, **kwargs):
for key, value in kwargs.items():
if hasattr(self, key):
setattr(self, key, value)
def __repr__(self):
return '%s, %d years old' % (self.name, self.age)
For this example we’ll convert our Person instances to Python dictionaries, where each key with a value JSON can handle (string for the name and integer for the age attribute):
from configviper import converters
class PersonConverter(converters.Converter):
def to_json(self, value):
# value should be an instance of Person
return { 'name': value.name, 'age': value.age }
def to_python(self, value):
# value will be deserialized from JSON as a Python dictonary
# just like the returned by to_json method
return Person(**value)
Now you can apply your converter to a config-path on stabilization, like this:
from configviper import ConfigViper
values = (
('sys.owner', Person(name='John Doe', age=37), PersonConverter(),),)
conf = ConfigViper()
conf.stabilize(values)
print conf.sys.owner
# expected "John Doe, 37 years old"
conf.set('sys.owner', Person(name='Alice Foo', age=25))
The resulting configuration file should looks like:
{
"sys": {
"owner": {
"name": "Alice Foo",
"age": 25
}
}
}