views:

86

answers:

3

I have a simple app which requires a many-to-many relationship to be configured as part of its set-up. For example, the app requires a list of repository URLs, a list of users and for each user, a subset of the repository URLs.

I first thought of using a config.py file similar to the following:

repositories = {
    'repo1': 'http://svn.example.com/repo1/',
    'repo2': 'http://svn.example.com/repo2/',
    'repo3': 'http://svn.example.com/repo3/',
}
user_repository_mapping = {
    'person_A': ['repo1', 'repo3'],
    'person_B': ['repo2'],
    'person_C': ['repo1', 'repo2']
}

which I could import. But this is quite messy as the config file lives outside my python-path and I would rather use a standard configuration approach such as using ini files or YAML.

Is there an elegant way of configuring a relationship such as this without importing a Python directly?

+1  A: 

If you like the idea of representing structure by indentation (like in Python) then YAML will be perfect for you. If you don't want to rely on whitespace and prefer explicit syntax then better go with JSON. Both are easy to understand and popular, which means that there are Python libraries out there.

Additional advantage is the fact that, in contrast to using standard Python code, you can be sure that your configuration file can contains only data and no arbitrary code that will get executed.

Adam Byrtek
A: 

The tactic I use is to put the whole application in a class, and then instead of having an importable config file, allow the user to pass in configuration to the constructor. Or, in more complicated cases they could even subclass the application class to add members or change behaviours. Although this does require a little knowledge of Python syntax in order to configure the app, it's not really that difficult, and much more flexible than the ini/markup config file approach.

So you example you could have an invoke-script outside the pythonpath looking like:

#!/usr/bin/env python

import someapplication

class MySomeApplication(someapplication.Application):
    repositories = {
       'repo1': 'http://svn.example.com/repo1/',
       'repo2': 'http://svn.example.com/repo2/',
       'repo3': 'http://svn.example.com/repo3/',
    }
    user_repository_mapping = {
        'person_A': ['repo1', 'repo3'],
        'person_B': ['repo2'],
        'person_C': ['repo1', 'repo2']
    }

MySomeApplication().run()

Then to have a second configuration they can swap out or even run at the same time, you simply cope the invoke-script and change the settings in it.

bobince
+2  A: 

I would store the config in JSON format. For example:

cfg = """
{
    "repositories": {
        "repo1": "http://svn.example.com/repo1/",
        "repo2": "http://svn.example.com/repo2/",
        "repo3": "http://svn.example.com/repo3/"
    },
    "user_repository_mapping": {
        "person_A": ["repo1", "repo3"],
        "person_B": ["repo2"],
        "person_C": ["repo1", "repo2"]
    }
}
"""

import simplejson as json
config = json.loads(cfg)
person = "person_A"
repos = [config['repositories'][r] for r in config['user_repository_mapping'][person]]
print repos
John Keyes
This is just the ticket - thanks!
DavidWinterbottom