3

I want to store this verbose output of pycosat to a string:

import pycosat
cnf = [[1, -5, 4], [-1, 5, 3, 4], [-3, -4]]
pycosat.solve(cnf,verbose=5)

I found various solutions, e.g. Capture stdout from a script in Python

However the solutions based on stringIO() don't capture the pycosat output. The output gets printed normally, and an empty string is captured.

I think this has to do with the fact that pycosat is a binding to the c-library picosat but I do not know how to deal with this.

This solution doesn't work either https://stackoverflow.com/a/29834357/4270148

Python will freeze at

out.stop()

ipython will also freeze at

sys.stdout = StringIO()

which may have something to do with it.

I did not try using the solutions using subprocess, because I need the local variable cnf, and it doesn't really make sense to pass it into a subprocess.

I don't know if it should be relevant, but I am using conda 3.14.1 on osx-64

Community
  • 1
  • 1
Tivaro
  • 177
  • 12

2 Answers2

1

The subprocess solution found here https://stackoverflow.com/a/5136686/4270148, actually works!

import subprocess
proc = subprocess.Popen(["python", "-c",
    "cnf = [[1, -5, 4], [-1, 5, 3, 4], [-3, -4]];\
    import pycosat;\
    pycosat.solve(cnf,verbose=5);"],
    stdout=subprocess.PIPE)
out = proc.communicate()[0]

I don't like that the way the program is passed (as an eval-string), but at least it works.

Community
  • 1
  • 1
Tivaro
  • 177
  • 12
0

Sometimes it can be a problem as Mac OS has only virtual terminal, and real console is hidden. So stdout and stderr can sometimes act oddly. (Very rare occasions)

Try using stderr instead:

from cStringIO import StringIO
import sys
import pycosat
cnf = [[1, -5, 4], [-1, 5, 3, 4], [-3, -4]]
sys.stderr = StringIO()
pycosat.solve(cnf,verbose=5)
solution = sys.stderr.getvalue()
sys.stderr = sys.__stderr__
print solution

If this still does you no good, then pycosat is using another filedescriptor for its output (neither stdout nor stder) and you will have to connect to it manually.

Dalen
  • 4,128
  • 1
  • 17
  • 35
  • Unfortunatly, this does not capture the output either. You suggest that I connect to it manually. By this do you mean that I will have to edit the bindings? It seems to me that stdout is used in the c-file to print the results https://github.com/ContinuumIO/pycosat/blob/master/picosat.c#L1216 https://github.com/ContinuumIO/pycosat/blob/master/picosat.c#L3499 – Tivaro Oct 19 '15 at 12:55
  • You said that when using stdout process blocks. So it may be that it does use stdout but that it makes some changes to terminal through FCNTL. So as StringIO() is not a terminal that cannot be applied and thing blocks. In that case you should be able to fool pycosat by putting some pseudoterminal into sys.stdout. See the module tty. It will write on one end to it, and you'll read it from another. – Dalen Oct 19 '15 at 15:41
  • By -manually- I meant that if another filedescriptor is used that is not sys.stdout nor sys.stderr, but it is bridged to them, you would be able to wrap it using os.fdopen(), and then redirect it in some way. But opening new terminals is not usual. To see whether any other tty is created, take a look at all opened files after importing pycosat. Command lsof on Linux, I am not booted in Mac to check now, perhaps is the same. – Dalen Oct 19 '15 at 15:49