8

I'm working on a program in Python for Windows, and would like to save variables and user preferences so that I can recall them even after the program has been terminated and restarted.

Is there an ideal way to do this on Windows machines? Would _winreg and the Windows registry be suited for this task? Or do I need to create some sort of database of my own?

Parker
  • 8,539
  • 10
  • 69
  • 98

8 Answers8

10

Python2 has ConfigParser, which is configparser, in Python3:

import ConfigParser, os

config = ConfigParser.ConfigParser()
config.readfp(open('defaults.cfg'))
config.read(['site.cfg', os.path.expanduser('~/.myapp.cfg')])

Even on windows, you should be aware that the registry is a wretched hive of scum and villainy, and that you should not be using it to store your python app configurations.

Warren P
  • 65,725
  • 40
  • 181
  • 316
  • 12
    `you should be aware that the registry is a wretched hive of scum and villainy` This is the most important thing you should take from this entire question. – Falmarri May 18 '12 at 17:29
  • Thank you! I haven't used Windows extensively in a while, and was never quite sure of the overall view of the registry, I'll be sure to stay clear of it if I can – Parker May 19 '12 at 16:37
  • In addition to `configparser` let's not forget `configobj`, I use both. `configparser` for the simple stuff and `configobj` when things get a little more involved. Both use `ini` type, human readable, text files, to store variable values against keywords, within sections. – Rolf of Saxony Mar 23 '21 at 19:19
5

You're usually going to want to store it in a configuration folder in the "home" folder. That's easy on *nix systems, more difficult in windows, because you actually need to get the "application data" directory. This usually works for me:

import os
if os.name != "posix":
    from win32com.shell import shellcon, shell
    homedir = "{}\\".format(shell.SHGetFolderPath(0, shellcon.CSIDL_APPDATA, 0, 0))
else:
    homedir = "{}/".format(os.path.expanduser("~"))

After you have the homedirectory, you should create a folder named after your project:

if not os.path.isdir("{0}.{1}".format(homedir,projectname)):
    os.mkdir("{0}.{1}".format(homedir,projectname))

Then you can make a config file in that folder and write your options to it in the format of your choosing (my personal favorite is in an XML).

Josiah
  • 3,266
  • 24
  • 24
  • Doesn't `os.path.expanduser` work everywhere? Why write more code? – Warren P May 17 '12 at 22:37
  • Just using expanduser won't get you the application data folder, which is different depending on if you are on winXP or win7. Doing it this way gets you the application data directory regardless of your windows OS. – Josiah May 17 '12 at 22:39
  • 1
    Many Python apps on Windows put data in your home folder, not in its subdirectory for app data. I find this ideal, because the behaviour is the same on Windows and Linux. (Python, TortoiseHG, and a whole raft of other Python apps.) – Warren P May 17 '12 at 22:48
  • 1
    That's an acceptable way to handle it, but I believe the preferred method (That is, MS' given standard) is to put it in the application data folder. It depends on how you want to handle it. – Josiah May 17 '12 at 22:51
  • @WarrenP: `because the behaviour is the same on Windows and Linux` That's actually a big issue on linux. There's so many . files in linux that clutter your `~` directory it's kind of gotten overwhelming. I like the trend of using the `~/.config/` folder, but it's not as widespread as I'd like. Currently I have 31 apps using `.config`, including a couple of my own that I haven't published. – Falmarri May 18 '12 at 17:37
  • Sure, fine, Falmari, do it your way. But forget about MS ApplicationData folders, is what I'm saying. – Warren P May 18 '12 at 22:40
  • @WarrenP Do you have a valid reason to not put them in the ApplicationData folders? It's 3 extra lines of code, and the Windows "home" directory (C:/username) is not used in even close to the same way as the linux home directory is. – Josiah May 19 '12 at 00:40
  • Thanks! I'm going to go with this as the best answer as I was completely unaware of the existence of the MS AppData directory before this, and your example code was extremely beneficial – Parker May 19 '12 at 16:36
  • Josiah -- It boils down to following Microsoft guidelines (making your way better if you care about Microsoft's guidelines) or following a general Python-apps-that-happen-to-run-on-Windows but are rather "meh" about Microsoft's chosen flavor of deeply nesting subdirectories. I fit in the latter category, as do many other things (Python, Mercurial, TortoiseHg, etc) that are very well written indeed. Your choice really. – Warren P May 20 '12 at 13:07
  • 2
    @Josiah, why don't you use the os.path.join method rather than explicitly specifying a forward or backslash based on your filesystem? – wesanyer Feb 10 '16 at 18:38
  • @wesanyer I could say that it's because it's less code and still more or less reliable to describe it this way, but frankly I think the correct answer is that I wrote this 4 years ago, and anything you do 4 years ago was done by an idiot. – Josiah Feb 11 '16 at 18:47
  • @josiah haha, fair enough. I just wanted to be sure I wasn't missing some sort of best practice pertaining to os.path.join – wesanyer Feb 11 '16 at 18:49
4

Unless I"m missing something, regex has nothing to do with the windows registry. Just store a config file somewhere, like the user's home directory or whatever. At least that's what I'd do on linux. Store a file somewhere in ~/.config/

Falmarri
  • 47,727
  • 41
  • 151
  • 191
1

If you want to store just key-value pairs of preferences, do it in a text config file. If you want to store python structures, do it with pickle or shelve. If you need a light, hassle free, rdbms use sqlite.

rantanplan
  • 7,283
  • 1
  • 24
  • 45
1

While the pickle module is an obvious choice, the files it writes will be non-human-readable. For configuration files, it would be good if your configuration file was a simple text format that your users can read or even edit. So, I recommend you use JSON and the json module.

steveha
  • 74,789
  • 21
  • 92
  • 117
  • 1
    ConfigParser reads and writes files that look like INI files, and is built in also. JSON is great for >2 levels of key+value hierarchy though. – Warren P May 18 '12 at 22:39
  • @WarrenP, I have been using JSON a lot recently, and I guess it has become my go-to format! But I can hardly argue against using `ConfigParser` for config files; good idea. – steveha May 21 '12 at 05:51
1

There are several ways, devided into two main directions

  • Access the Windows registry with the _winreg module.

Using the registry it is nontrivial to transfer the settings to another machine or to inspect them or back them up; you'd have to use regedit for those.

The other way store the preferences in a file in the user's 'My Documents' folder. This makes it easier to move the settings to another machine or user, and doesn't mix your program's settings with those of a host of other applications. So things like backing them up and restoring them are easier; you just copy one file. If you choose a text format, it is also easier to inspect and debug the settings.

  • Put your settings in a list, tuple or dictionary and save them with the cPickle module. This is probably one of the easiest methods. On the downside, while pickled data uses an ASCII format by default, it is not human-readable.
  • Use the ConfigParser module to save and load config files in a similar structure as Windows' .ini files. These files are human-readable.
  • Use the json module to store settings in json format. These files are human-readable.
  • Save the preferences as Python expressions to a text file, load it with execfile(). N.B. This could be used to execute arbitrary code, so there are safety considerations. But on the upside, it is very easy and readable.
Roland Smith
  • 42,427
  • 3
  • 64
  • 94
0

To save variables, I recommend using pickle

BrtH
  • 2,610
  • 16
  • 27
0

To determine where to store preferences I recommend using the appdirs package to locate the appropriate "application data", "preferences", or "home" directory for your operating system:

from appdirs import user_data_dir
appname = "SuperApp"
appauthor = "Acme"
appdata_dirpath = user_data_dir(appname, appauthor)
# 'C:\\Users\\me\\AppData\\Local\\Acme\\SuperApp' on Windows
# '/Users/me/Library/Application Support/SuperApp' on macOS
# '/home/me/.local/share/SuperApp' on Linux

import os
os.makedirs(appdata_dirpath, exist_ok=True)

Then inside that directory you can write a file, with many different options for the file format:

  • Key-Value Strings? Consider an INI file, which you can read/write using the built-in configparser.ConfigParser module.

  • Nested Dicts, Lists, Strings, and Integers? Consider JSON, which you can read/write using the built-in json module.

  • Have more advanced needs? Such as storing a large number of preference items, or a need to store binary data? Consider a sqlite database, using the built-in sqlite3 module.

Although it is possible to use the pickle module I don't recommend it because the config files are not human-readable.

David Foster
  • 6,931
  • 4
  • 41
  • 42