I am attempting to remove a [section] from an ini file using Python's ConfigParser library.
>>> import os
>>> import ConfigParser
>>> os.system("cat a.ini")
[a]
b = c
0
>>> p = ConfigParser.SafeConfigParser()
>>> s = open('a.ini', 'r+')
>>> p.readfp(s)
>>> p.sections()
['a']
>>> p.remove_section('a')
True
>>> p.sections()
[]
>>> p.write(s)
>>> s.close()
>>> os.system("cat a.ini")
[a]
b = c
0
>>>
It appears that the remove_section() happens only in-memory and when asked to write back the results to the ini file, there is nothing to write.
Any ideas on how to remove a section from the ini file and persist it?
Is the mode that I'm using to open the file incorrect?
I tried with 'r+' & 'a+' and it didn't work. I cannot truncate the entire file since it may have other sections that shouldn't be deleted.
You need to open the file in write mode eventually. This will truncate it, but that is okay because when you write to it, the ConfigParser object will write all the sections that are still in the object.
What you should do is open the file for reading, read the config, close the file, then open the file again for writing and write it. Like this:
with open("test.ini", "r") as f:
p.readfp(f)
print(p.sections())
p.remove_section('a')
print(p.sections())
with open("test.ini", "w") as f:
p.write(f)
# this just verifies that [b] section is still there
with open("test.ini", "r") as f:
print(f.read())
You need to change file position using file.seek. Otherwise, p.write(s) writes the empty string (because the config is empty now after remove_section) at the end of the file.
And you need to call file.truncate so that content after current file position cleared.
p = ConfigParser.SafeConfigParser()
with open('a.ini', 'r+') as s:
p.readfp(s) # File position changed (it's at the end of the file)
p.remove_section('a')
s.seek(0) # <-- Change the file position to the beginning of the file
p.write(s)
s.truncate() # <-- Truncate remaining content after the written position.
Related
I am try to create some temporal files and make some operations on them inside a loop. Then I will access the information on all of the temporal files. And do some operations with that information. For simplicity I brought the following code that reproduces my issue:
import tempfile
tmp_files = []
for i in range(40):
tmp = tempfile.NamedTemporaryFile(suffix=".txt")
with open(tmp.name, "w") as f:
f.write(str(i))
tmp_files.append(tmp.name)
string = ""
for tmp_file in tmp_files:
with open(tmp_file, "r") as f:
data = f.read()
string += data
print(string)
ERROR:
with open(tmp_file, "r") as f: FileNotFoundError: [Errno 2] No such file or directory: '/tmp/tmpynh0kbnw.txt'
When I look on /tmp directory (with some time.sleep(2) on the loop) I see that the file is deleted and only one is preserved. And for that the error.
Of course I could handle to keep all the files with the flag tempfile.NamedTemporaryFile(suffix=".txt", delete=False). But that is not the idea. I would like to hold the temporal files just for the running time of the script. I also could delete the files with os.remove. But my question is more why this happen. Because I expected that the files hold to the end of the running. Because I don't close the file on the execution (or do I?).
A lot of thanks in advance.
tdelaney does already answer your actual question.
I just would like to offer you an alternative to NamedTemporaryFile. Why not creating a temporary folder which is removed (with all files in it) at the end of the script?
Instead of using a NamedTemporaryFile, you could use tempfile.TemporaryDirectory. The directory will be deleted when closed.
The example below uses the with statement which closes the file handle automatically when the block ends (see John Gordon's comment).
import os
import tempfile
with tempfile.TemporaryDirectory() as temp_folder:
tmp_files = []
for i in range(40):
tmp_file = os.path.join(temp_folder, f"{i}.txt")
with open(tmp_file, "w") as f:
f.write(str(i))
tmp_files.append(tmp_file)
string = ""
for tmp_file in tmp_files:
with open(tmp_file, "r") as f:
data = f.read()
string += data
print(string)
By default, a NamedTemporaryFile deletes its file when closed. its a bit subtle, but tmp = tempfile.NamedTemporaryFile(suffix=".txt") in the loop causes the previous file to be deleted when tmp is reassigned. One option is to use the delete=False parameter. Or, just keep the file open and seek to the beginning after the write.
NamedTemporaryFile is already a file object - you can write to it directly without reopening. Just make sure the mode is "write plus" and in text, not binary mode. Put the code an a try/finally block to make sure the files are really deleted at the end.
import tempfile
tmp_files = []
try:
for i in range(40):
tmp = tempfile.NamedTemporaryFile(suffix=".txt", mode="w+")
tmp.write(str(i))
tmp.seek(0)
tmp_files.append(tmp)
string = ""
for tmp_file in tmp_files:
data = tmp_file.read()
string += data
finally:
for tmp_file in tmp_files:
tmp_file.close()
print(string)
I need to change the items in the list saved in other python file
file A.py
items = ['A','B','C']
file B.py
import A
A.items.append('D')
it works, but when I restart the script it switch to the previous version.
You need to store the data in a file to save it.
In this script I have the items list in file A, file B adds 'D' to the list, and then adds
it to a txt file.
You can print the txt file in file A after you run file B to see the new items list. The new list gets saved as new_items
If you run file B multiple times, it will add the list more then once.
File A:
items = ['A','B','C']
#prints out the txt file
with open("items.txt","r") as f:
new_items = f.read()
new_items = new_items.split()
print(new_items)
f.close()
File B:
import A
#Adds 'D' to the items list and stores it as a new variable
A.items.append('D')
items = A.items
#Writes the data to a txt file
with open('items.txt', 'a') as f:
f.write(str(items))
When an application exits, the memory used by that application is freed. This is why we need files, we can write our data into files. Also actions that your code does while running don't affects any source code.
If your items will be a list of strings you can use a lightweight solution like this:
#a.py
import os, ast
items = ['A','B','C']
file = "data.txt" # the file we will write our data in
if os.path.exists(file): # if our file exists
with open(file, "r") as f: # open it in 'r'ead mode
items = ast.literal_eval(f.read()) # read it and evalute
else: # if our file doesn't exists
with open(file, "w") as f: # open it in 'w'rite mode
f.write(str(items)) # write str(items) into file
#b.py
import a
a.items.append("D")
with open("data.txt", "w") as f: # open our file in 'w'rite mode
f.write(str(a.items)) # save a.items
As a general solution, you can also use pickle or json module for saving lists or other objects.
Docs:
ast.literal_eval, open,
os.path
This question already has answers here:
Why doesn't calling a string method (such as .replace or .strip) modify (mutate) the string?
(3 answers)
Closed 3 years ago.
I am trying to display my python file in html and therefore I would like to replace every time the file jumps to a newline with < br> but the program I've written is not working.
I've looked on here and tried changing the code around a bit I have gotten different results but not the ones I need.
with open(path, "r+") as file:
contents = file.read()
contents.replace("\n", "<br>")
print(contents)
file.close()
I want to have the file display < br> every time I have a new line but instead the code dosen't change anything to the file.
Here is an example program that works:
path = "example"
contents = ""
with open(path, "r") as file:
contents = file.read()
new_contents = contents.replace("\n", "<br>")
with open(path, "w") as file:
file.write(new_contents)
Your program doesn't work because the replace method does not modify the original string; it returns a new string.
Also, you need to write the new string to the file; python won't do it automatically.
Hope this helps :)
P.S. a with statement automatically closes the file stream.
Your code reads from the file, saves the contents to a variable and replaces the newlines. But the result is not saved anywhere. And to write the result into a file you must open the file for writing.
with open(path, "r+") as file:
contents = file.read()
contents = contents.replace("\n", "<br>")
with open(path, "w+") as file:
contents = file.write(contents)
there are some issues in this code snippet.
contents.replace("\n", "<br>") will return a new object which replaced \n with <br>, so you can use html_contents = contents.replace("\n", "<br>") and print(html_contents)
when you use with the file descriptor will close after leave the indented block.
Try this:
import re
with open(path, "r") as f:
contents = f.read()
contents = re.sub("\n", "<br>", contents)
print(contents)
Borrowed from this post:
import tempfile
def modify_file(filename):
#Create temporary file read/write
t = tempfile.NamedTemporaryFile(mode="r+")
#Open input file read-only
i = open(filename, 'r')
#Copy input file to temporary file, modifying as we go
for line in i:
t.write(line.rstrip()+"\n")
i.close() #Close input file
t.seek(0) #Rewind temporary file to beginning
o = open(filename, "w") #Reopen input file writable
#Overwriting original file with temporary file contents
for line in t:
o.write(line)
t.close() #Close temporary file, will cause it to be deleted
I wrote python code to search a pattern in a tcl file and replace it with a string, it prints the output but the same is not saved in the tcl file
import re
import fileinput
filename=open("Fdrc.tcl","r+")
for i in filename:
if i.find("set qa_label")!=-1:
print(i)
a=re.sub(r'REL.*','harsh',i)
print(a)
filename.close()
actual result
set qa_label
REL_ts07n0g42p22sadsl01msaA04_2018-09-11-11-01
set qa_label harsh
Expected result is that in my file it should reflect the same result as above but it is not
You need to actually write your changes back to disk if you want to see them affected there. As #ImperishableNight says, you don't want to do this by trying to write to a file you're also reading from...you want to write to a new file. Here's an expanded version of your code that does that:
import re
import fileinput
fin=open("/tmp/Fdrc.tcl")
fout=open("/tmp/FdrcNew.tcl", "w")
for i in fin:
if i.find("set qa_label")!=-1:
print(i)
a=re.sub(r'REL.*','harsh',i)
print(a)
fout.write(a)
else:
fout.write(i)
fin.close()
fout.close()
Input and output file contents:
> cat /tmp/Fdrc.tcl
set qa_label REL_ts07n0g42p22sadsl01msaA04_2018-09-11-11-01
> cat /tmp/FdrcNew.tcl
set qa_label harsh
If you wanted to overwrite the original file, then you would want to read the entire file into memory and close the input file stream, then open the file again for writing, and write modified content to the same file.
Here's a cleaner version of your code that does this...produces an in memory result and then writes that out using a new file handle. I am still writing to a different file here because that's usually what you want to do at least while you're testing your code. You can simply change the name of the second file to match the first and this code will overwrite the original file with the modified content:
import re
lines = []
with open("/tmp/Fdrc.tcl") as fin:
for i in fin:
if i.find("set qa_label")!=-1:
print(i)
i=re.sub(r'REL.*','harsh',i)
print(i)
lines.append(i)
with open("/tmp/FdrcNew.tcl", "w") as fout:
fout.writelines(lines)
Open a tempfile for writing the updated file contents and open the file for writing.
After modifying the lines, write it back in the file.
import re
import fileinput
from tempfile import TemporaryFile
with TemporaryFile() as t:
with open("Fdrc.tcl", "r") as file_reader:
for line in file_reader:
if line.find("set qa_label") != -1:
t.write(
str.encode(
re.sub(r'REL.*', 'harsh', str(line))
)
)
else:
t.write(str.encode(line))
t.seek(0)
with open("Fdrc.tcl", "wb") as file_writer:
file_writer.writelines(t)
when I try to write data to a file I get no errors but when I try to read it back nothing is in the file. What am I doing wrong?
test = open('/Users/MYUSER/Desktop/test.txt', 'r+')
test.write("RANDOME STRING\n")
test.read()
''
You need to move the file pointer to the start of the file using file.seek before calling .read(). When you write something to a file, the file pointer moves to the end of file, that's why calling .read() on the file object was returning an empty string.
Demo:
>>> test = open('abc1', 'r+')
>>> test.write('foo')
>>> test.read()
''
>>> test.seek(0)
>>> test.read()
'foo'