views:

1155

answers:

13

I'm programming (in Python) a website which will have users. These users will have a number of settings, such as their choice of colour scheme, etc. I'm happy to store these as plain text files, and security is not an issue.

The way I currently see it is: there's a dictionary, where all the keys are users and the values are dictionaries with the users' settings in them.

For example, userdb["bob"]["colour_scheme"] would have the value "blue".

What's the best way to store it on file? Pickling the dictionary?

Are there better ways of doing what I'm trying to do, anyway?

+3  A: 

Using cPickle on the dictionary would be my choice. Dictionaries are a natural fit for these kind of data, so given your requirements I see no reason not to use them. That, unless you are thinking about reading them from non-python applications, in which case you'd have to use a language neutral text format. And even here you could get away with the pickle plus an export tool.

Vinko Vrsalovic
The problem with cPickle in this case is that you can not load settings for just one user, you have to load it all. shelve scales better and it is equally simple to use.
Toni Ruža
+1  A: 

This sounds like a job for (quickly enter and exit a phonebooth) XML!

(Or yaml or JSON or whatever your favorite data interchange language is)

Rik
A: 

If you have a database, I might suggest storing the settings in the database. However, it sounds like ordinary files might suit your environment better.

You probably don't want to store all the users settings in the same file, because you might run into trouble with concurrent access to that one file. If you stored each user's settings as a dictionary in their own pickled file, then they would be able to act independently.

Pickling is a reasonable way to store such data, but unfortunately the pickle data format is notoriously not-human-readable. You might be better off storing it as repr(dictionary) which will be a more readable format. To reload the user settings, use eval(open("file").read()) or something like that.

Greg Hewgill
+4  A: 

I don't tackle the question which one is best. If you want to handle text-files, I'd consider ConfigParser -module. Another you could give a try would be simplejson or yaml. You could also consider a real db table.

For instance, you could have a table called userattrs, with three columns:

  • Int user_id
  • String attribute_name
  • String attribute_value

If there's only few, you could store them into cookies for quick retrieval.

Cheery
+3  A: 

Here's the simplest way. Use simple variables and import the settings file.

Call the file userprefs.py

# a user prefs file
color = 0x010203
font = "times new roman"
position = ( 12, 13 )
size = ( 640, 480 )

In your application, you need to be sure that you can import this file. You have many choices.

  1. Using PYTHONPATH. Require PYTHONPATH be set to include the directory with the preferences files.

    a. An explicit command-line parameter to name the file (not the best, but simple)

    b. An environment variable to name the file.

  2. Extending sys.path to include the user's home directory

Example

import sys
import os
sys.path.insert(0,os.path.expanduser("~"))
import userprefs 
print userprefs.color
S.Lott
Wouldn't you then have to have a separate file for each user? That seems like a lot of overhead.
Mark Biek
@Mark Biek: " These users will have a number of settings," It sounds like per-user settings to me. Possibly misreading the question.
S.Lott
I voted this up because it's a great solution for my problem -- which isn't exactly the one the question asks.I want a config file for a command line application, which is a fairly different use case.
Joe Germuska
+1  A: 

If human readablity of configfiles matters an alternative might be the ConfigParser module which allows you to read and write .ini like files. But then you are restricted to one nesting level.

Anders Waldenborg
+2  A: 

I would use shelve or an sqlite database if I would have to store these setting on the file system. Although, since you are building a website you probably use some kind of database so why not just use that?

Toni Ruža
A: 

Is there are particular reason you're not using the database for this? it seems the normal and natural thing to do - or store a pickle of the settings in the db keyed on user id or something.

You haven't described the usage patterns of the website, but just thinking of a general website - but I would think that keeping the settings in a database would cause much less disk I/O than using files.

OTOH, for settings that might be used by client-side code, storing them as javascript in a static file that can be cached would be handy - at the expense of having multiple places you might have settings. (I'd probably store those settings in the db, and rebuild the static files as necessary)

Steven Adams
A: 

I agree with the reply about using Pickled Dictionary. Very simple and effective for storing simple data in a Dictionary structure.

Corey Goldberg
A: 

If you don't care about being able to edit the file yourself, and want a quick way to persist python objects, go with pickle. If you do want the file to be readable by a human, or readable by some other app, use ConfigParser. If you need anything more complex, go with some sort of database, be it relational (sqlite), or object-oriented (axiom, zodb).

Jeremy Cantrell
+1  A: 

For a database-driven website, of course, your best option is a db table. I'm assuming that you are not doing the database thing.

If you don't care about human-readable formats, then pickle is a simple and straightforward way to go. I've also heard good reports about simplejson.

If human readability is important, two simple options present themselves:

Module: Just use a module. If all you need are a few globals and nothing fancy, then this is the way to go. If you really got desperate, you could define classes and class variables to emulate sections. The downside here: if the file will be hand-edited by a user, errors could be hard to catch and debug.

INI format: I've been using ConfigObj for this, with quite a bit of success. ConfigObj is essentially a replacement for ConfigParser, with support for nested sections and much more. Optionally, you can define expected types or values for a file and validate it, providing a safety net (and important error feedback) for users/administrators.

David Eyk
+4  A: 

I would use the ConfigParser module, which produces some pretty readable and user-editable output for your example:

[bob]
colour_scheme: blue
british: yes
[joe]
color_scheme: that's 'color', silly!
british: no

The following code would produce the config file above, and then print it out:

import sys
from ConfigParser import *

c = ConfigParser()

c.add_section("bob")
c.set("bob", "colour_scheme", "blue")
c.set("bob", "british", str(True))

c.add_section("joe")
c.set("joe", "color_scheme", "that's 'color', silly!")
c.set("joe", "british", str(False))

c.write(sys.stdout)  # this outputs the configuration to stdout
                     # you could put a file-handle here instead

for section in c.sections(): # this is how you read the options back in
    print section
    for option in c.options(section):
            print "\t", option, "=", c.get(section, option)

print c.get("bob", "british") # To access the "british" attribute for bob directly

Note that ConfigParser only supports strings, so you'll have to convert as I have above for the Booleans. See effbot for a good run-down of the basics.

Noah
A: 

The built-in sqlite3 module would probably be far simpler than most alternatives, and gets you ready to update to a full RDBMS should you ever want or need to.

Just Some Guy