67

Django uses real Python files for settings, Trac uses a .ini file, and some other pieces of software uses XML files to hold this information.

Are one of these approaches blessed by Guido and/or the Python community more than another?

Steven Hepting
  • 12,394
  • 8
  • 40
  • 50
  • 2
    According to wikipedia, "ini" files were predominant in windows where it's now deprecated. So IMO, you should skip that choice. – WhyNotHugo May 15 '12 at 04:15
  • From Microsoft: [Why are INI files deprecated in favor of the registry?](https://blogs.msdn.microsoft.com/oldnewthing/20071126-00/?p=24383) – jkdev Oct 31 '16 at 15:38
  • The link above is rotten. New link form Microsoft: [Why are INI files deprecated in favor of the registry?](https://devblogs.microsoft.com/oldnewthing/20071126-00/?p=24383) November 26th, 2007 – pabouk - Ukraine stay strong Apr 29 '21 at 08:05

14 Answers14

38

Depends on the predominant intended audience.

If it is programmers who change the file anyway, just use python files like settings.py

If it is end users then, think about ini files.

lprsd
  • 84,407
  • 47
  • 135
  • 168
  • 35
    What does a typical `settings.py` file look like? – Hamish Grubijan Feb 19 '11 at 17:41
  • 3
    I think he is referring to the Django settings.py file. It is a valid python file with declarations for strings, tuples, lists and other variables. – pcx May 09 '12 at 12:26
  • 3
    I agree on the first part, but if end users need to alter it, you something the ConfigParser can read. – WhyNotHugo May 15 '12 at 04:16
  • I know this topic is old, but how a `settings.py` file would store configuration to be read at runtime like a `.ini` file? A settings.py leads me to think that there'll be a Settings class that will orchestrate how settings are setted and unsetted, but how they would be stored? Currently I'm not using a settings.py file but I am using a `.env` file to store configuration options because a .ini file looks very "changeable" by the user. Either way, using .env feels just wrong cause it's not very structured and also could lead to wrong modifications by the user. – dsenese Jun 13 '23 at 13:51
32

As many have said, there is no "offical" way. There are, however, many choices. There was a talk at PyCon this year about many of the available options.

brianz
  • 7,268
  • 4
  • 37
  • 44
  • 6
    @mac, I found it: http://blip.tv/pycon-us-videos-2009-2010-2011/a-configuration-comparison-in-python-2006550 – utdemir Dec 28 '11 at 15:30
  • @utdemir - Thank you, I updated the original answer with your link, removing my original comment... – mac Dec 28 '11 at 17:41
20

Don't know if this can be considered "official", but it is in standard library: 14.2. ConfigParser — Configuration file parser.

This is, obviously, not an universal solution, though. Just use whatever feels most appropriate to the task, without any necessary complexity (and — especially — Turing-completeness! Think about automatic or GUI configurators).

drdaeman
  • 11,159
  • 7
  • 59
  • 104
  • 1
    json is in standard library too, along with all kinds of xml-processing modules – SilentGhost Jun 08 '09 at 17:44
  • 7
    Sure JSON is standard, but this is module is called "Configuration File Parser" for a reason. I find it's great for read/writing, and pretty easy to understand for both novice and non-novice users. – WhyNotHugo May 15 '12 at 04:12
  • @SilentGhost JSON format is not very suitable for human-editable configuration files. --- 1. It does not support comments. 2. Many brackets and double quotes could be confusing for human editing. – pabouk - Ukraine stay strong May 02 '21 at 13:27
16

I use a shelf ( http://docs.python.org/library/shelve.html ):

shelf = shelve.open(filename)
shelf["users"] = ["David", "Abraham"]
shelf.sync() # Save
Zippo
  • 15,850
  • 10
  • 60
  • 58
  • 11
    From docs, "Because the shelve module is backed by pickle, it is insecure to load a shelf from an untrusted source. Like with pickle, loading a shelf can execute arbitrary code". If this question is intended to guide novices, everyone should point them to configparser module, otherwise to JSON or custom file. INI file sections are more defined (readable) than JSON, even if you pretify it's code. [] brackes adds a bit sense of bold, so sections are easily to watch. – m3nda Feb 29 '16 at 16:13
12

Just one more option, PyQt. Qt has a platform independent way of storing settings with the QSettings class. Underneath the hood, on windows it uses the registry and in linux it stores the settings in a hidden conf file. QSettings works very well and is pretty seemless.

jhufford
  • 470
  • 2
  • 10
8

There is no blessed solution as far as I know. There is no right or wrong way to storing app settings neither, xml, json or all types of files are fine as long as you are confortable with. For python I personally use pypref it's very easy, cross platform and straightforward.

pypref is very useful as one can store static and dynamic settings and preferences ...

from pypref import Preferences

#  create singleton preferences instance
pref = Preferences(filename="preferences_test.py")

# create preferences dict
pdict = {'preference 1': 1, 12345: 'I am a number'}

# set preferences. This would automatically create preferences_test.py 
# in your home directory. Go and check it.
pref.set_preferences(pdict)

# lets update the preferences. This would automatically update 
# preferences_test.py file, you can verify that. 
pref.update_preferences({'preference 1': 2})

# lets get some preferences. This would return the value of the preference if
# it is defined or default value if it is not.
print pref.get('preference 1')

# In some cases we must use raw strings. This is most likely needed when
# working with paths in a windows systems or when a preference includes
# especial characters. That's how to do it ...
pref.update_preferences({'my path': " r'C:\Users\Me\Desktop' "})

# Sometimes preferences to change dynamically or to be evaluated real time.
# This also can be done by using dynamic property. In this example password
# generator preference is set using uuid module. dynamic dictionary
# must include all modules name that must be imported upon evaluating
# a dynamic preference
pre = {'password generator': "str(uuid.uuid1())"}
dyn = {'password generator': ['uuid',]}
pref.update_preferences(preferences=pre, dynamic=dyn)

# lets pull 'password generator' preferences twice and notice how
# passwords are different at every pull
print pref.get('password generator')
print pref.get('password generator')

# those preferences can be accessed later. Let's simulate that by creating
# another preferences instances which will automatically detect the 
# existance of a preferences file and connect to it
newPref = Preferences(filename="preferences_test.py")

# let's print 'my path' preference
print newPref.get('my path')
Cobry
  • 4,348
  • 8
  • 33
  • 49
6

One of the easiest ways which is use is using the json module. Save the file in config.json with the details as shown below.

Saving data in the json file:

{

    "john"  : {
        "number" : "948075049" , 
        "password":"thisisit" 
    }    
}

Reading from json file:

import json

#open the config.json file 

with open('config.json') as f:
    mydata = json.load(f) ; 

#Now mydata is a python dictionary 

print("username is " , mydata.get('john').get('number') , " password is " , mydata.get('john').get('password')) ;
Eric Aya
  • 69,473
  • 35
  • 181
  • 253
Natesh bhat
  • 12,274
  • 10
  • 84
  • 125
  • 1
    Note that `mydata.get('john').get('number')` is not a good code. If there is no `john` key in data then `mydata.get('john')` will return `None`, and `.get('number')` will raise an exception. Using `.get` assumes that you want to handle missing data gracefully; so better do this: `mydata.get('john', {}).get('number')` - this won't result in exception, unless `mydata` itself is not a `dict`. – MarSoft Feb 25 '18 at 22:12
6

I am not sure that there is an 'official' way (it is not mentioned in the Zen of Python :) )- I tend to use the Config Parser module myself and I think that you will find that pretty common. I prefer that over the python file approach because you can write back to it and dynamically reload if you want.

Shane C. Mason
  • 7,518
  • 3
  • 26
  • 33
4

It depends largely on how complicated your configuration is. If you're doing a simple key-value mapping and you want the capability to edit the settings with a text editor, I think ConfigParser is the way to go.

If your settings are complicated and include lists and nested data structures, I'd use XML or JSON and create a configuration editor.

For really complicated things where the end user isn't expected to change the settings much, or is more trusted, just create a set of Python classes and evaluate a Python script to get the configuration.

Kamil Kisiel
  • 19,723
  • 11
  • 46
  • 56
2

For web applications I like using OS environment variables: os.environ.get('CONFIG_OPTION')

This works especially well for settings that vary between deploys. You can read more about the rationale behind using env vars here: http://www.12factor.net/config

Of course, this only works for read-only values because changes to the environment are usually not persistent. But if you don't need write access they are a very good solution.

dbader
  • 10,081
  • 2
  • 22
  • 17
  • Not bad, but when having lots of vars to set it might more convenient to do it the Django way: store it into a file and set different files depending on a single environment variable (in django, DJANGO_SETTINGS_MODULE). This way you can have dynamic and writable values as well. – danius Apr 03 '15 at 15:52
  • If you're using this method then you might also want to take a look at https://github.com/theskumar/python-dotenv – smilly92 Sep 21 '16 at 10:18
0

Not an official one but this way works well for all my Python projects.

pip install python-settings

Docs here: https://github.com/charlsagente/python-settings

You need a settings.py file with all your defined constants like:

# settings.py

DATABASE_HOST = '10.0.0.1'

Then you need to either set an env variable (export SETTINGS_MODULE=settings) or manually calling the configure method:

# something_else.py

from python_settings import settings
from . import settings as my_local_settings

settings.configure(my_local_settings) # configure() receives a python module

The utility also supports Lazy initialization for heavy to load objects, so when you run your python project it loads faster since it only evaluates the settings variable when its needed

# settings.py

from python_settings import LazySetting
from my_awesome_library import HeavyInitializationClass # Heavy to initialize object

LAZY_INITIALIZATION = LazySetting(HeavyInitializationClass, "127.0.0.1:4222") 
# LazySetting(Class, *args, **kwargs)

Just configure once and now call your variables where is needed:

# my_awesome_file.py

from python_settings import settings 

print(settings.DATABASE_HOST) # Will print '10.0.0.1'
charls
  • 39
  • 2
  • This library uses Python files to store configuration. This option has huge security disadvantages as the configuration file could contain any executable code - possibly malicious or unintentionally failing a wrong way. – pabouk - Ukraine stay strong May 02 '21 at 13:22
0

The accepted answer "settings.py" only takes care of "reading" config information. The information is stored by human (or other program) before the python program is running, and the information (usually) is loaded at the starting phase of the program.

But they can't handle the situation that during the program, the settings are changed, and the information need to store for future use.

An INI file, or a JSON file, or an XML file would be capable of reading from and writing into. ConfigParser can take care of INI files. JSON has many functions to perform the same tasks.

I would suggest to use JSON for it's popularity, versatility (easy to fit in different format of the settings).

Ben L
  • 171
  • 1
  • 9
0

It is more of convenience. There is no official way per say. But using XML files would make sense as they can be manipulated by various other applications/libraries.

Checksum
  • 3,220
  • 3
  • 23
  • 24
  • 5
    the same can be said about json, ini files, etc. – SilentGhost Jun 08 '09 at 16:26
  • @Darren: Not true if you are using Python 2.5 or higher (because of ElementTree) – Imran Jun 08 '09 at 19:04
  • @becomingGuru: XML Design Goal 6: "XML documents should be human-legible and reasonably clear." – S.Lott Jun 08 '09 at 19:09
  • 4
    @S. Lott - Sure they should but that does not mean that they ever really are. You must admit that it is much easier to edit an ini or properties file than an xml doc. – Shane C. Mason Jun 08 '09 at 20:16
  • 4
    @Shane C. Mason: Humans *are* supposed to read/write XML. As a practical matter, this is really hard, and I don't use XML much because of it. I use JSON or CSV files -- much easier to edit. But @becomingGuru's comment is -- in a narrow technical sense -- incorrect. – S.Lott Jun 08 '09 at 22:33
  • Assembly language is also meant to be human-readable, but the people who can successfully read it are few. And I wouldn't use it for a configuration either. – WhyNotHugo May 15 '12 at 04:13
-1

why would Guido blessed something that is out of his scope? No there is nothing particular blessed.

SilentGhost
  • 307,395
  • 66
  • 306
  • 293
  • 2
    upvoted, because you actually answered OPs question ("No there is nothing particular blessed"). The downvotes might come from the first part of your answer: Having a community shared "best practice" can really help getting started in a new language / new project... – Daren Thomas Jun 08 '09 at 18:10
  • I understand the role of Guido's rulings in relation to core, stdlib development, etc., but the question asks about basic use where good practice can hardly be defined. – SilentGhost Jun 08 '09 at 18:17