1

I have a python script that calls a system program and reads the output from a file out.txt, acts on that output, and loops. However, it doesn't work, and a close investigation showed that the python script just opens out.txt once and then keeps on reading from that old copy. How can I make the python script reread the file on each iteration? I saw a similar question here on SO but it was about a python script running alongside a program, not calling it, and the solution doesn't work. I tried closing the file before looping back but it didn't do anything.

EDIT: I already tried closing and opening, it didn't work. Here's the code:

import subprocess, os, sys

filename = sys.argv[1]
file = open(filename,'r')
foo = open('foo','w')
foo.write(file.read().rstrip())
foo = open('foo','a')
crap = open(os.devnull,'wb')
numSolutions = 0

while True:
    subprocess.call(["minisat", "foo", "out"], stdout=crap,stderr=crap)
    out = open('out','r')
    if out.readline().rstrip() == "SAT":
        numSolutions += 1
        clause = out.readline().rstrip()
        clause = clause.split(" ")
        print clause
        clause = map(int,clause)
        clause = map(lambda x: -x,clause)
        output = ' '.join(map(lambda x: str(x),clause))
        print output
        foo.write('\n'+output)
        out.close()
    else:
        break

print "There are ", numSolutions, " solutions."
Elliot Gorokhovsky
  • 3,610
  • 2
  • 31
  • 56
  • You can close it and open it again. – tdelaney Jan 07 '15 at 22:16
  • are you writing to the file each time? – Padraic Cunningham Jan 07 '15 at 22:25
  • Hey, are you still there? Its quite likely that the system program deletes the old `out.txt` and writes a new one. On linux at least, the open file handle will point to the old unlinked file and will never see the new data. Since closing/opening is the obvious solution, can you tell us if it worked? – tdelaney Jan 07 '15 at 23:02
  • @tdelaney It is supposed to overwrite out.txt. I am using minisat to count the number of solutions to a SAT problem by multiplying the old solution by -1 and appending it to the input file. So the algorithm is minisat input output, multiply output by -1, append to input, repeat. The problem is that output doesn't change after the initial read. And I did close it at the end of the loop and reopen, it didn't work. I posted code in my question. – Elliot Gorokhovsky Jan 07 '15 at 23:22
  • A couple of things to try... do `if os.path.isfile("out"): os.remove("out")` before running and temporarily pipe stdout and err to a file to see if some other bad thing is going on. – tdelaney Jan 07 '15 at 23:33
  • And do a `foo.flush()` after the write. – tdelaney Jan 07 '15 at 23:35
  • @tdelaney Thanks! foo.flush() was necessary, the rest didn't matter. I didn't realize you had to flush your writes in python! – Elliot Gorokhovsky Jan 08 '15 at 00:31
  • @tdelaney feel free to post your answer – Elliot Gorokhovsky Jan 08 '15 at 00:32

3 Answers3

3

You need to flush foo so that the external program can see its latest changes. When you write to a file, the data is buffered in the local process and sent to the system in larger blocks. This is done because updating the system file is relatively expensive. In your case, you need to force a flush of the data so that minisat can see it.

    foo.write('\n'+output)
    foo.flush()
tdelaney
  • 73,364
  • 6
  • 83
  • 116
1

I rewrote it to hopefully be a bit easier to understand:

import os
from shutil import copyfile
import subprocess
import sys

TEMP_CNF = "tmp.in"
TEMP_SOL = "tmp.out"
NULL = open(os.devnull, "wb")

def all_solutions(cnf_fname):
    """
    Given a file containing a set of constraints,
    generate all possible solutions.
    """
    # make a copy of original input file
    copyfile(cnf_fname, TEMP_CNF)

    while True:
        # run minisat to solve the constraint problem
        subprocess.call(["minisat", TEMP_CNF, TEMP_SOL], stdout=NULL,stderr=NULL)

        # look at the result
        with open(TEMP_SOL) as result:
            line = next(result)
            if line.startswith("SAT"):
                # Success - return solution
                line = next(result)
                solution = [int(i) for i in line.split()]
                yield solution
            else:
                # Failure - no more solutions possible
                break

        # disqualify found solution
        with open(TEMP_CNF, "a") as constraints:
            new_constraint = " ".join(str(-i) for i in sol)
            constraints.write("\n")
            constraints.write(new_constraint)

def main(cnf_fname):
    """
    Given a file containing a set of constraints,
    count the possible solutions.
    """
    count = sum(1 for i in all_solutions(cnf_fname))
    print("There are {} solutions.".format(count))

if __name__=="__main__":
    if len(sys.argv) == 2:
        main(sys.argv[1])
    else:
        print("Usage: {} cnf.in".format(sys.argv[0]))
Hugh Bothwell
  • 55,315
  • 8
  • 84
  • 99
0

You take your file_var and end the loop with file_var.close().

for ... :
    ga_file = open(out.txt, 'r')
    ... do stuff
    ga_file.close()

Demo of an implementation below (as simple as possible, this is all of the Jython code needed)...

__author__ = ''
import time

var = 'false'
while var == 'false':
    out = open('out.txt', 'r')
    content = out.read()
    time.sleep(3)
    print content
    out.close()

generates this output:

2015-01-09, 'stuff added'
2015-01-09, 'stuff added'           # <-- this is when i just saved my update
2015-01-10, 'stuff added again :)'  # <-- my new output from file reads

I strongly recommend reading the error messages. They hold quite a lot of information.

I think the full file name should be written for debug purposes.

25r43q
  • 613
  • 4
  • 16