The testing code:
import ConfigParser
config = ConfigParser.ConfigParser()
config.read('test_config.ini')
orig_str = """line1\r\nline2"""
config_str = config.get('General', 'orig_str')
print orig_str == config_str
and the content of test_config.ini is:
[General]
orig_str = line1\r\nline2
What I want is the config_str can be the same value as the orig_str.
Any help would be appreciated!
If you want to write multiline configuration values, you just need to prepend a space at the beginning of the following lines. For example:
[General]
orig_str = line1
line2
returns 'line1\nline2' in my OS (Linux), but maybe in a different OS might return the '\r' as well. Otherwise, it would be easy to replace '\n' with '\r\n' as you need.
I'd say that whatever library you're using to encode the message should take care of the replacement. Anyway, if that's not the case, you can create your own ConfigParser as follows:
from ConfigParser import ConfigParser
class MyConfigParser(ConfigParser):
def get(self, section, option):
return ConfigParser.get(self, section, option).replace('\n', '\r\n')
config = MyConfigParser()
config.read('test_config.ini')
orig_str = """line1\r\nline2"""
config_str = config.get('General', 'orig_str')
print orig_str == config_str # Prints True
Related
I need to create a file in the following format:
option1 = 99
option2 = 34
do_it = True
...
When I use ConfigParser, I have to put all my data into a section with an artificial name, and then it creates a file which starts with [SECTION].
import ConfigParser
ini_writer = ConfigParser.ConfigParser()
ini_writer.add_section('SECTION')
ini_writer.set('SECTION', 'option1', 99)
ini_writer.set('SECTION', 'option2', 34)
ini_writer.set('SECTION', 'do_it', True)
with open('my.ini', 'w') as f:
ini_writer.write(f)
How can I change it so it outputs the file without the dummy section header? I would like to do it using Python 2.7, but a Python 3 solution would help too (the idea is that I could port it to Python 2.7).
This related question shows how to read such files using minor tweaks to the code.
[NB: the following is written for Python 3; you would need to make a couple of minor changes to make it run under Python 2.]
Maybe something like this; here, I write to an io.StringIO object in memory, then take everything but the first line and write that out to the target file.
import configparser
import io
buf = io.StringIO()
ini_writer = configparser.ConfigParser()
ini_writer.set('DEFAULT', 'option1', '99')
ini_writer.set('DEFAULT', 'option2', '34')
ini_writer.set('DEFAULT', 'do_it', 'True')
ini_writer.write(buf)
buf.seek(0)
next(buf)
with open('my.ini', 'w') as fd:
fd.write(buf.read())
By using the section name DEFAULT we avoid having to create a new section first.
This results in:
$ cat my.ini
option1 = 99
option2 = 34
do_it = True
As ConfigParser doesn't support this I personally would probably opt to monkeypatch the write method to support non-section writing.
from configparser import ConfigParser
def _write_section_custom(self, fp, section_name, section_items, delimiter):
for key, value in section_items:
value = self._interpolation.before_write(self, section_name, key, value)
if value is not None or not self._allow_no_value:
value = delimiter + str(value).replace('\n', '\n\t')
else:
value = ''
fp.write('{}{}\n'.format(key, value))
fp.write('\n')
ini_writer = ConfigParser()
ConfigParser._write_section = _write_section_custom
ini_writer.add_section('SECTION')
ini_writer.set('SECTION', 'option1', '99')
ini_writer.set('SECTION', 'option2', '34')
ini_writer.set('SECTION', 'do_it', 'True')
with open('my.ini', 'w') as f:
ini_writer.write(f)
With that I get:
$ cat my.ini
option1 = 99
option2 = 34
do_it = True
I've tested this under Python 3.8 so you would need to test/adjust for 2.7. Also bear in mind that the reading of the custom ini would need to be adapted/monkeypatched. You could also wrap this into a custom ConfigParser class of your own so that you have it reusable wherever you need it in your project.
The bingo.config has a string with a random integer in it.
Inside the file, it looks like
boothNumber="2"
My template.config file has the same string with a different integer or number.
I am trying to replace this with the current integer in bingo.config
My problem is that the number in template.config is not being replaced by the number in bingo.config
It's replacing the number in template.config with the literal string "r'(?<=boothNumber=")\d+'"
So template.config ends up looking like
boothNumber="r'(?<=boothNumber=")\d+'"
instead of
boothNumber="2"
It looks like my issue is stemming from how I save the variable "pattern" in the "readconfig" function.
Any ideas on how I can save the integer from bingo.config into a proper variable that can be used?
import os
import shutil
import fileinput
import re # used to replace string
import sys # prevents extra lines being inputed in config
# example: sys.stdout.write
def convertconfig(pattern):
source = "template.config"
with fileinput.FileInput(source, inplace=True, backup='.bak') as file:
for line in file:
match = r'(?<=boothNumber=")\d+'
sys.stdout.write(re.sub(match, pattern, line))
def readconfig():
source = "bingo.config"
pattern = r'(?<=boothNumber=")\d+' # !!!!!!!!!! This probably needs fixed
with fileinput.FileInput(source, inplace=True, backup='.bak') as file:
for line in file:
if re.search(pattern, line):
fileinput.close()
convertconfig(pattern)
def copyfrom(servername):
source = r'//' + servername + '/c$/remotedirectory'
dest = r"C:/myprogram"
file = "bingo.config"
try:
shutil.copyfile(os.path.join(source, file), os.path.join(dest, file))
except:
print ("Error")
readconfig()
# begin here
os.system('cls' if os.name == 'nt' else 'clear')
array = []
with open("serverlist.txt", "r") as f:
for servername in f:
copyfrom(servername.strip())
I am using PEP8 module of python inside my code.
import pep8
pep8_checker = pep8.StyleGuide(format='pylint')
pep8_checker.check_files(paths=['./test.py'])
r = pep8_checker.check_files(paths=['./test.py'])
This is the output:
./test.py:6: [E265] block comment should start with '# '
./test.py:23: [E265] block comment should start with '# '
./test.py:24: [E302] expected 2 blank lines, found 1
./test.py:30: [W293] blank line contains whitespace
./test.py:35: [E501] line too long (116 > 79 characters)
./test.py:41: [E302] expected 2 blank lines, found 1
./test.py:53: [E501] line too long (111 > 79 characters)
./test.py:54: [E501] line too long (129 > 79 characters)
But this result is printed on terminal and the final value that is assigned to 'r' is 8 (i.e. total numbers of errors).
I want to store these errors in a variable. How can I do this?
EDIT:
here is the test.py file: http://paste.fedoraproject.org/347406/59337502/raw/
There are at least two ways to do this. The simplest is to redirect sys.stdout to a text file, then read the file at your leisure:
import pep8
import sys
saved_stdout = sys.stdout
sys.stdout = open('pep8.out', 'w')
pep8_checker = pep8.StyleGuide(format='pylint')
pep8_checker.check_files(paths=['./test.py'])
r = pep8_checker.check_files(paths=['./test.py'])
sys.stdout.close()
sys.stdout = saved_stdout
# Now you can read "pep.out" into a variable
Alternatively you can write to a variable using StringIO:
import pep8
import sys
# The module name changed between python 2 and 3
if sys.version_info.major == 2:
from StringIO import StringIO
else:
from io import StringIO
saved_stdout = sys.stdout
sys.stdout = StringIO()
pep8_checker = pep8.StyleGuide(format='pylint')
pep8_checker.check_files(paths=['./test.py'])
r = pep8_checker.check_files(paths=['./test.py'])
testout = sys.stdout.getvalue()
sys.stdout.close()
sys.stdout = saved_stdout
# testout contains the output. You might wish to testout.spilt("\n")
Parsing wrong value from ini file, how can i parse the username from username= field not from the value?
1) Ini file stored with predefined presets, which i need to read in python
$ cat /var/tmp/file.ini
banner=QUESTIONS sentence
network=lan
programming=pytohn
url=http\://pbx/register?username=E300B1&password=1234&option=localip&localip=
username=E300B1
password=1234
server=pbx
2) Code: i was trying seems wrong for username/password field
import re,os, time, socket, datetime, threading, subprocess, logging, gtk, gobject
logging.basicConfig(filename='/var/tmp/log.log',level=logging.DEBUG)
def readini(findme):
f = open('/var/tmp/file.ini', "r")
for line in f:
if line:
if findme in line:
r= line.split("=")
return r[1].replace("\\n", "").rstrip()
host = readini("server")
username = preadini("username")
password = readini("password")
command = """curl 'http://%s/a/b?username=%s&password=%s&language=EN'""" % (host, username, password)
logging.debug( command )
os.system( command )
3) outputs (wrong):
DEBUG:root:curl 'http://192.168.1.10/a/b?username=http\://pbx/register?username&password=http\://pbx/register?username&language=EN'
4) expected output was:
DEBUG:root:curl 'http://192.168.1.10/a/b?username=E300B1&password=1234&language=EN'
The problem is that your condition if findme in line does not work with your file. In your file, the string "username" is in the line defining the url -- which is why you're seeing the output that you're seeing.
url=http\://pbx/register?username=E300B1&password=1234&option=localip&localip=
A better approach would be:
def readini(findme):
f = open('/var/tmp/file.ini', "r")
for line in f:
if "=" in line:
key,val = line.split("=",1)
if findme in key:
return val.replace("\\n", "").rstrip()
Using the optional int arg to split guarantees that the list returned has length two and that it will actually be the key,val pair defined by that line.
I'm trying to implement a simple helper class to interact with java-properties files. Fiddling with multiline properties I encountered a problem, that I can not get solved, maybe you can?
The unittest in the class first writes a multiline-property spanning over two lines to the property-file, then re-reads it and checks for equality. That just works. Now, if i use the class to add a third line to the property, it re-reads it with additional backslashes that I can't explain.
Here is my code:
#!/usr/bin/env python3
# -*- coding=UTF-8 -*-
import codecs
import os, re
import fileinput
import unittest
class ConfigParser:
reProp = re.compile(r'^(?P<key>[\.\w]+)=(?P<value>.*?)(?P<ext>[\\]?)$')
rePropExt = re.compile(r'(?P<value>.*?)(?P<ext>[\\]?)$')
files = []
def __init__(self, pathes=[]):
for path in pathes:
if os.path.isfile(path):
self.files.append(path)
def getOptions(self):
result = {}
key = ''
val = ''
with fileinput.input(self.files, inplace=False) as fi:
for line in fi:
m = self.reProp.match(line.strip())
if m:
key = m.group('key')
val = m.group('value')
result[key] = val
else:
m = self.rePropExt.match(line.rstrip())
if m:
val = '\n'.join((val, m.group('value')))
result[key] = val
fi.close()
return result
def setOptions(self, updates={}):
options = self.getOptions()
options.update(updates)
with fileinput.input(self.files, inplace=True) as fi:
for line in fi:
m = self.reProp.match(line.strip())
if m:
key = m.group('key')
nval = options[key]
nval = nval.replace('\n', '\\\n')
print('{}={}'.format(key,nval))
fi.close()
class test(unittest.TestCase):
files = ['test.properties']
props = {'test.m.a' : 'Johnson\nTanaka'}
def setUp(self):
for file in self.files:
f = codecs.open(file, encoding='utf-8', mode='w')
for key in self.props.keys():
val = self.props[key]
val = re.sub('\n', '\\\n', val)
f.write(key + '=' + val)
f.close()
def teardown(self):
pass
def test_read(self):
c = configparser(self.files)
for file in self.files:
for key in self.props.keys():
result = c.getOptions()
self.assertEqual(result[key],self.props[key])
def test_write(self):
c = ConfigParser(self.files)
changes = {}
for key in self.props.keys():
changes[key] = self.change_value(self.props[key])
c.setOptions(changes)
result = c.getOptions()
print('changes: ')
print(changes)
print('result: ')
print(result)
for key in changes.keys():
self.assertEqual(result[key],changes[key],msg=key)
def change_value(self, value):
return 'Smith\nJohnson\nTanaka'
if __name__ == '__main__':
unittest.main()
Output of the testrun:
C:\pyt>propertyfileparser.py
changes:
{'test.m.a': 'Smith\nJohnson\nTanaka'}
result:
{'test.m.a': 'Smith\nJohnson\\\nTanaka'}
Any hints welcome...
Since you are adding a backslash in front of new-lines when you are writing, you have to also remove them when you are reading. Uncommenting the line that substitutes '\n' with '\\n' solves the problem, but I expect this also means the file syntax is incorrect.
This happens only with the second line break, because you separate the value into an "oval" and an "nval" where the "oval" is the first line, and the "nval" the rest, and you only do the substitution on the nval.
It's also overkill to use regexp replacing to replace something that isn't a regexp. You can use val.replace('\n', '\\n') instead.
I'd do this parser very differently. Well, first of all, I wouldn't do it at all, I'd use an existing parser, but if I did, I'd read the file, line by line, while handling the line continuation issue, so that I had exactly one value per item in a list. Then I'd parse each item into a key and a value with a regexp, and stick that into a dictionary.
You instead parse each line separately and join continuation lines to the values after parsing, which IMO is completely backwards.