15

I need to edit a configuration file through python and i tried searching on stackoverflow and google and they don't cover my situation, since i need to replace lines in the file and perform matches in my search.

Also, what i found covers how to do it for one line, i will be performing at least 8 line replacements in the file and I would like to know if there is a cleaner and more elegant way of doing this than putting 10 replace(foo, bar) lines altogether.

I need to "match" lines like "ENABLEPRINTER", "PRINTERLIST", "PRNT1.PORT". I want to match thesse text and ignore whatever follows (ex: "=PRNT1, PRNT2").

So i would do something like

replace('ENABLEPRINTER', 'y')
replace('PRINTERLIST', 'PRNT3) 

The file looks like this:

ENABLEPRINTER=n
PRINTERLIST=PRNT1, PRNT2

PRNT1.PORT=9600
PRNT1.BITS=8

Also note these files are about 100 lines and i need to edit about 10 of them.

Thank you very much for your help.

UPDATE:

Using the code posted by @J.F. Sebastian, i'm now getting the following error:

configobj.ParseError: Parse error in value at line 611.

Line 611 of the file is:

log4j.appender.dailyRollingFile.DatePattern='.'yyyy-MM-d

So the problem is with the ' character.

If I comment out that line, the script is working fine with the code posted by @J.F. Sebastian.

mstefan
  • 439
  • 1
  • 6
  • 10

2 Answers2

7
import re 
pat = re.compile('ENABLEPRINTER|PRINTERLIST|PRNT1.PORT')

def jojo(mat,dic = {'ENABLEPRINTER':'y',
                    'PRINTERLIST':'PRNT3',
                    'PRNT1.PORT':'734'} ):
    return dic[mat.group()]

with open('configfile','rb+') as f:
    content = f.read()
    f.seek(0,0)
    f.write(pat.sub(jojo,content))
    f.truncate()

Before:

ENABLEPRINTER=n 
PRINTERLIST=PRNT1, PRNT2  

PRNT1.PORT=9600 
PRNT1.BITS=8

After:

y=n 
PRNT3==PRNT1, PRNT2  

734=9600
PRNT1.BITS=8

Too simple to be definitive. Say what are the errors or weaknesses.

The advantage of regexes is they can be modulated easily to particular cases.

.

EDIT:

I've just seen that:

"what i want to do is assign a new value to the variable "

you could inform of that earlier !

Could you give an exemple of file before / after , please.

.

EDIT 2

Here's the code to change the values of certain variables in a file:

import re
from os import fsync

def updating(filename,dico):

    RE = '(('+'|'.join(dico.keys())+')\s*=)[^\r\n]*?(\r?\n|\r)'
    pat = re.compile(RE)

    def jojo(mat,dic = dico ):
        return dic[mat.group(2)].join(mat.group(1,3))

    with open(filename,'rb') as f:
        content = f.read() 

    with open(filename,'wb') as f:
        f.write(pat.sub(jojo,content))



#-----------------------------------------------------------

vars = ['ENABLEPRINTER','PRINTERLIST','PRNT1.PORT']
new_values = ['y','PRNT3','8310']
what_to_change = dict(zip(vars,new_values))


updating('configfile_1.txt',what_to_change)

Before:

ENABLEPRINTER=n 
PRINTERLIST=PRNT1, PRNT2  

PRNT1.PORT=9600 
PRNT1.BITS=8

After:

ENABLEPRINTER=y 
PRINTERLIST=PRNT3

PRNT1.PORT=8310 
PRNT1.BITS=8
eyquem
  • 26,771
  • 7
  • 38
  • 46
  • 1
    Hi! Thank you for your very detailes answer! I'm sorry i created so much confusion with my question, i did a terrible job at explaining myself. The last code that you posted to change certain variables in a file isnt working for me. – mstefan Mar 15 '11 at 13:47
  • 1
    I'm getting this error: Traceback (most recent call last): File "D:\script\editconf.py", line 26, in updating('printer.properties',what_to_change) File "D:\script\editconf.py", line 16, in updating f.write(pat.sub(jojo,content)) TypeError: can't use a string pattern on a bytes-like object – mstefan Mar 15 '11 at 13:49
  • @mstefan Are you with Python 3.x ? – eyquem Mar 15 '11 at 14:56
  • @mstefan Try to define ``RE = b'(('+'|'.join(dico.keys())+')\s*=)[^\r\n]*?(\r?\n|\r)' `` or something like that. I am with Python 2.7 and I can't test. Maybe , since RE is an agregation, it has to be ``RE = b'((' + b'|'.join(dico.keys()) + b')\s*=)[^\r\n]*?(\r?\n|\r)' `` . Maybe the keys of dico must be made bytes too ? – eyquem Mar 15 '11 at 15:06
  • There is a method using the "ConfigParser" to specifically change settings on python "ini" files. Although practical, totally changes the file by removing the comments and so I gave up for the method proposed here when we want to change python "ini" files! For more information see http://stackoverflow.com/questions/27964134/change-value-in-ini-file-using-configparser-python. – Eduardo Lucio Jan 20 '16 at 20:08
5

If the file is in java.util.Properties format then you could use pyjavaproperties:

from pyjavaproperties import Properties

p = Properties()
p.load(open('input.properties'))

for name, value in [('ENABLEPRINTER', 'y'), ('PRINTERLIST', 'PRNT3')]:
    p[name] = value
p.store(open('output.properties', 'w'))

It is not very robust, but various fixes for it could benefit people who come next.


To replace multiple times in a short string:

for old, new in [('ENABLEPRINTER', 'y'), ('PRINTERLIST', 'PRNT3')]:
    some_string = some_string.replace(old, new)

To replace variables names in a configuration file (using configobj module):

import configobj

conf = configobj.ConfigObj('test.conf')

for old, new in [('ENABLEPRINTER', 'y'), ('PRINTERLIST', 'PRNT3')]:
    conf[new] = conf[old]
    del conf[old]
conf.write()

If by replace('ENABLEPRINTER', 'y') you mean assign y to the ENABLEPRINTER variable then:

import configobj

ENCODING='utf-8'
conf = configobj.ConfigObj('test.conf', raise_errors=True,
    file_error=True,           # don't create file if it doesn't exist
    encoding=ENCODING,         # used to read/write file
    default_encoding=ENCODING) # str -> unicode internally (useful on Python2.x)

conf.update(dict(ENABLEPRINTER='y', PRINTERLIST='PRNT3'))
conf.write()

It seems configobj is not compatible with:

name = '.'something

You could quote it:

name = "'.'something"

Or:

name = '.something'

Or

name = .something

conf.update() does something similar to:

for name, value in [('ENABLEPRINTER', 'y'), ('PRINTERLIST', 'PRNT3')]:
    conf[name] = value
jfs
  • 399,953
  • 195
  • 994
  • 1,670
  • nevermind, i found the python 3.x port here https://bitbucket.org/zubin71/configobj-py3. – mstefan Mar 14 '11 at 19:42
  • @mstefan: set `raise_errors=True` for the `ConfigObj()` and `.write()` calls. Set character encoding in the `ConfigObj()` call explicitly. "doesn't work" is too vague: what is in the 'test.conf' file? What do you get and what do you expect to see (update your question with examples of correct input/output)? What do `sys.version` and `configobj.__version__` contain? – jfs Mar 14 '11 at 20:53
  • 1
    My impression is that mstefan wants to change the value of the variable, and not the variable name. (Although he does not specify what he wants to have changed.) – Johan Mar 14 '11 at 22:09
  • @J.F. Sebastian: raise_errors helped realize that it is failing because the conf file im editing has a couple lines that have the ' symbol: dateformat = '.' yyyy-MM-dd asciiCode = ',165 so it is giving me a "ParseError: parse error in value at line X" – mstefan Mar 14 '11 at 22:21
  • sorry, formatting gabrled up my message. what i meant to say is that a few lines have the ' symbol which doesnt seem to play nicely with ConfigObj. Any ideas on how to work around those lines? – mstefan Mar 14 '11 at 22:22
  • @mstefan: update your question with examples of correct input/output – jfs Mar 14 '11 at 22:32
  • @J.F. Sebastian: yes indeed, what i want to do is assign a new value to the variable (update whatever value it currently has). – mstefan Mar 14 '11 at 23:05
  • @J.F. Sebastian: for some reason your update(dict()) is not working. ive been trying to find in the api the proper method and cant find it. the documentation is confusing. what is the difference between update and replace? and why are you using dict() ? – mstefan Mar 14 '11 at 23:06
  • @mstefan: `conf.update()` method is present in 'configobj 4.7.2'. It works the same as corresponding dictionary method http://docs.python.org/library/stdtypes.html#dict.update – jfs Mar 14 '11 at 23:11
  • @mstefan: I've updated the answer with an example of what `conf.update()` does. – jfs Mar 14 '11 at 23:30