2

I'm using Python 3.2 and the configparser module, and running into some problems. I need to read, then write to a config file. I tried the following:

import configparser
data = open('data.txt', 'r+')
a = configparser.ConfigParser()
a.read_file(data)
a['example']['test'] = 'red'
a.write(data)

The problem is that when I open data with r+, when I write to it the new information gets appended; it does not overwrite the old.

import configparser
data = open('data.txt', 'r')
a = configparser.ConfigParser()
a.read_file(data)
a['example']['test'] = 'red'
data = open('data.txt', 'w')
a.write(data)

This way ^ seems unsafe, because opening it with w empties the file. What if the program crashes before it has time to write? The configuration file is lost. Is the only solution to backup before opening with w?

Edit:

The following is also a possibility, but is it safe?

a.write(open('data.txt','w'))
Hypercube
  • 1,181
  • 2
  • 10
  • 16

2 Answers2

5

If you're really concerned about that, you can write to a temporary file, and then rename the temporary file to this one — if the config write fails, the original will be untouched; rename/move is usually atomic (though under Windows you might need to call MoveFileEx directly, instead of using os.rename), so you can be sure that you'll either have the old contents or the new contents, and the file won't be in any other state (sans any critical failures of the underlying filesystem, of course).

# ...
a['example']['test'] = 'red'

import tempfile, os
with tempfile.NamedTemporaryFile() as tmp:
    a.write(tmp)

    # or ctypes.windll.kernel32.MoveFileExW(tmp.name, 'data.txt', 2)
    # 2 = MOVEFILE_REPLACE_EXISTING 
    # I'll leave wrapping it in a cross-platform manner up to you
    os.rename(tmp.name, 'data.txt')
Cat Plus Plus
  • 125,936
  • 27
  • 200
  • 224
  • Thanks! That's a great idea. Too bad Windows uses another operation though. – Hypercube Jun 30 '11 at 01:25
  • 1
    I think it should be `tempfile.mkstemp()[-1]` or `tempfile.mktemp()` but the second one is not safe... – JBernardo Jun 30 '11 at 01:32
  • [msdn says MOVEFILE_REPLACE_EXISTING is 1](http://msdn.microsoft.com/en-us/library/windows/desktop/aa365240(v=vs.85).aspx), not 2 – jfs Oct 23 '12 at 08:59
0

This is what I would do as I ran into a similar scenario.

import configparser
data = open('data.txt', 'r+')
a = configparser.ConfigParser()
a.read_file(data)
a['example']['test'] = 'red'
data.truncate(0)#<--
data.seek(0)#<--
a.write(data)

This causes the file object to get truncated to zero. Then it resets the pointer to the beginning of the file. After that configparser can proceed like normal with an empty file object.

It should be noted that I did this in Python 3.

Benargee
  • 162
  • 1
  • 2
  • 8