Capture the output from function in real time python - python-2.7

I didn't find quite what I was looking for.
I want to obtain the output (stdout) from a python function in real time.
The actual problem is that I want to plot a graph (with cplot from sympy) with a progress bar in my UI. The argument verbose makes cplot output the progress to stdout.
sympy.mpmath.cplot(lambda z: z, real, imag, verbose=True)
The output would be something like:
0 of 71
1 of 71
2 of 71
...
And so on.
I want to capture line by line so I can make a progress bar. (I realize this might not be possible without implementing multithreading). I'm using python2.7 (mainly because I need libraries that aren't in python3)
So, ¿How do I achieve that?

You can capture stdout by monkeypatching sys.stdout. A good way to do it is using a context manager, so that it gets put back when you are done (even if the code raises an exception). If you don't use a context manager, be sure to put the original sys.stdout back using a finally block.
You'll need an object that is file-like, that takes the input and does what you want with it. Subclassing StringIO is a good start. Here's an example of a context manager that captures stdout and stderr and puts them in the result of the bound variable.
class CapturedText(object):
pass
#contextmanager
def captured(disallow_stderr=True):
"""
Context manager to capture the printed output of the code in the with block
Bind the context manager to a variable using `as` and the result will be
in the stdout property.
>>> from tests.helpers import capture
>>> with captured() as c:
... print('hello world!')
...
>>> c.stdout
'hello world!\n'
"""
import sys
stdout = sys.stdout
stderr = sys.stderr
sys.stdout = outfile = StringIO()
sys.stderr = errfile = StringIO()
c = CapturedText()
yield c
c.stdout = outfile.getvalue()
c.stderr = errfile.getvalue()
sys.stdout = stdout
sys.stderr = stderr
if disallow_stderr and c.stderr:
raise Exception("Got stderr output: %s" % c.stderr)
(source)
It works as shown in the docstring. You can replace StringIO() with your own class that writes the progress bar.

Another possibility would be to monkeypatch sympy.mpmath.visualization.print, since cplot uses print to print the output, and it uses from __future__ import print_function.
First, make sure you are using from __future__ import print_function if you aren't using Python 3, as this will otherwise be a SyntaxError.
Then something like
def progressbar_print(*args, **kwargs):
# Take *args and convert it to a progress output
progress(*args)
# If you want to still print the output, do it here
print(*args, **kwargs)
sympy.mpmath.visualization.print = progressbar_print
You might want to monkeypatch it in a custom function that puts it back, as other functions in that module might use print as well. Again, remember to do this using either a context manager or a finally block so that it gets put back even if an exception is raised.
Monkeypatching sys.stdout is definitely the more standard way of doing this, but I like this solution in that it shows that having print as a function can actually be useful.

Related

Closing Tkinter GUI from another function A and passes Tkinter variable to function A

This question is about programming in Python 2.7.x
I wanted to code a programme where there are two functions exist: one of those is a method to get input from the user, and the other one is to show the input. Both are supposed to be done in GUI. Let's call the first function as GET TEXT function, and the second as SHOW TEXT function; my strategy is to open a GUI, show a text box, and put a button to go to SHOW TEXT function. Then, the first line of the SHOW TEXT function is to close the window opened by the GET TEXT function, get the value of the input text, and print it in another GUI.
So, I tried doing this,
from Tkinter import *
import tkMessageBox
def texttobeenteredhere():
application = Tk()
textbox = Text(application)
textbox.pack()
submitbutton = Button(application, text="OK", command=showinputtext)
submitbutton.pack()
application.mainloop()
def showinputtext():
application.quit()
thetext = textbox.get()
print "You typed", thetext
texttobeenteredhere()
I got errors that I could not comprehend, but I hope you get my idea even though my explanation could be really bad. Please suggest a solution to my problem, where the GET TEXT function and SHOW TEXT function have to exist separately in the code.
EDIT:
Thanks Josselin for introducing the syntax class in python. What I actually wanted to say was, I want the programme to open a window to get input from the user, and then close the window, and finally open another window to show the input text. I am honestly new to this, but through my prior knowledge and guessing, I tried to modify the code to meet my expectation.
import Tkinter as tk
global passtext
class application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.textbox = tk.Text(self)
self.textbox.pack()
self.submitbutton = tk.Button(self, text="OK", command=self.showinputtext)
self.submitbutton.pack()
self.mainloop()
def showinputtext(self):
self.thetext = self.textbox.get("1.0", "end-1c")
print "You typed:", self.thetext
self.destroy()
class showtext(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.setthetext = tk.StringVar()
self.setthetext.set(passtext)
self.showthetext = tk.Label(self, textvariable=self.setthetext)
self.showthetext.pack()
self.submitbutton = tk.Button(self, text="OK", command=self.destroy)
self.submitbutton.pack()
self.mainloop()
# Launch the GUI
app = application()
# Access the entered text after closing the GUI
passtext = app.thetext
text = showtext()
My English can sometimes be not understandable, but this question is answered. Thank you very much.
There are 2 main problems in your code:
First, in your showinputtext function, you want to access elements of your GUI, but they are not defined within the scope of the function.
Second, when reading the content of a tk.Text widget, the .get() method takes 2 arguments (see this link).
To fix the first problem, the best is to define your application as a class, with an inner function taking the class instance self as input argument, such that application widgets can be called within the function.
Code:
import Tkinter as tk
class application(tk.Tk):
def __init__(self):
tk.Tk.__init__(self)
self.textbox = tk.Text(self)
self.textbox.pack()
self.submitbutton = tk.Button(self, text="OK", command=self.showinputtext)
self.submitbutton.pack()
self.mainloop()
def showinputtext(self):
self.thetext = self.textbox.get("1.0", "end-1c")
print "You typed:", self.thetext
self.destroy()
# Launch the GUI
app = application()
# Access the entered text after closing the GUI
print "you entered:", app.thetext

PyQt4: Set QTextedit as the default sys.stdout

I have a 2 scripts:
script_1: performs some calculations and and prints the answers in the command line.
script_2: imports script_1 and then connects some of the functions in script_1 to pyqt4 slots.
script_1 contains no PyQt4 code
script_2 contains any relevant PyQt4 code
The reason I have my code in two scripts is so that I can modify all the "algorithms" and calculations in script_1 and without worrying about script_2 which is always changing (adding colors, buttons, and other widgets.)
When I am running script_1 it is useful to view all the output in the command line, but when I am running script_2, I am looking at a PyQt gui which has a QTextEdit widget that is blank. I would like all the text that appears in the command line to go into the QTextEdit box but I can't find a way to do that.
Is there an easy or any way to accomplish this?
You don't need to fully redirect input to the QTextEdit, just try to catch printing and append message to the QTextEdit:
class Log(object):
def __init__(self, edit):
self.out = sys.stdout
self.textEdit = edit
def write(self, message):
self.out.write(message)
self.textEdit.append(message)
def flush(self):
self.out.flush()
#...
if __name__ == '__main__':
app = QApplication(sys.argv)
print("will not be in textedit")
edit = QTextEdit()
edit.show()
sys.stdout = Log(edit)
print("will be in textedit")

Python tk(): No window appears when using in scripts (console works)

I have the following problem with this easy script:
from Tkinter import *
root = Tk()
while 1:
pass
I think, after the 2nd line everyone would expect a Tkinter window would appear. But it does not!
If I put this line into the Python console (without the endless-while-loop), it works.
[I wanted to add an image here, but as I'm new I'm to allowed to :-(]
But running the script (double-clicking on the *.py file in the Windows Explorer) results only in an empty Python console!
Background:
Actually I want to use Snack for Python. This is based on Tkinter. That means I have to create an Tk() instance first. Everything works fine in the Python console. But I want to write a bigger program with at least one Python script thus I cannot type the whole program into the console everytime :-)
I have installed Python 2.7 and Tcl/Tk 8.5 (remember: it works in the console)
EDIT: So here's my solution:
First, I create a class CSoundPlayer:
from Tkinter import*
import tkSnack
class CSoundPlayer:
def __init__(self, callbackFunction):
self.__activated = False
self.__callbackFunction = callbackFunction
self.__sounds = []
self.__numberOfSounds = 0
self.__root = Tk()
self.__root.title("SoundPlayer")
tkSnack.initializeSnack(self.__root)
def __mainFunction(self):
self.__callbackFunction()
self.__root.after(1, self.__mainFunction)
pass
def activate(self):
self.__activated = True
self.__root.after(1, self.__mainFunction)
self.__root.mainloop()
def loadFile(self, fileName):
if self.__activated:
self.__sounds.append(tkSnack.Sound(load=fileName))
self.__numberOfSounds += 1
# return the index of the new sound
return self.__numberOfSounds - 1
else:
return -1
def play(self, soundIndex):
if self.__activated:
self.__sounds[soundIndex].play()
else:
return -1
Then, the application itself must be implemented in a class thus the main() is defined when handed over to the CSoundPlayer() constructor:
class CApplication:
def __init__(self):
self.__programCounter = -1
self.__SoundPlayer = CSoundPlayer(self.main)
self.__SoundPlayer.activate()
def main(self):
self.__programCounter += 1
if self.__programCounter == 0:
self.__sound1 = self.__SoundPlayer.loadFile("../mysong.mp3")
self.__SoundPlayer.play(self.__sound1)
# here the cyclic code starts:
print self.__programCounter
CApplication()
As you can see, the mainloop() is called not in the constructor but in the activate() method. This is because the CApplication won't ever get the reference to CSoundPlayer object because that stucks in the mainloop.
The code of the class CApplication itself does a lot of overhead. The actual "application code" is placed inside the CApplication.main() - code which shall be executed only once is controlled by means of the program counter.
Now I put it to the next level and place a polling process of the MIDI Device in the CApplication.main(). Thus I will use MIDI commands as trigger for playing sound files. I hope the performance is sufficient for appropriate latency.
Have you any suggestions for optimization?
You must start the event loop. Without the event loop, tkinter has no way to actually draw the window. Remove the while loop and replace it with mainloop:
from Tkinter import *
root = Tk()
root.mainloop()
If you need to do polling (as mentioned in the comments to the question), write a function that polls, and have that function run every periodically with after:
def poll():
<do the polling here>
# in 100ms, call the poll function again
root.after(100, poll)
The reason you don't need mainloop in the console depends on what you mean by "the console". In IDLE, and perhaps some other interactive interpreters, tkinter has a special mode when running interactively that doesn't require you call mainloop. In essence, the mainloop is the console input loop.

How can I add a callback or hook to a Python builtin class method?

I am trying to gather information on files being opened and closed so I can keep track of which processes is doing what. I work with users that will not systematically use custom I/O functions and methods so I would like to change the behavior of builtins.
I figured out a way to change the open function. It might not be optimal, but it works.
import logging
import os
import sys
import io
import logging
import __builtin__
def custom_open(file_name, access_mode, buffering = 0):
logging.debug('Opening file ' + file_name)
return __builtin__.open(file_name, access_mode, buffering)
logging.getLogger('').setLevel(logging.DEBUG)
open = custom_open
f = open('workfile', 'w')
f.write('This is a test\n')
f.close()
What I would now like to do is change the behavior of the file close method. I tried a few things but nothing works.
To elaborate a little on my comment, since nobody else seems to be submitting an answer:
# Create a custom file class
class custom_file(file):
def close(self):
# do logging
super(file, self).close()
# create a custom file opener
def custom_open(*args, **kwargs):
# do logging
return custom_file(*args, **kwargs)
# Set local `open` to point to your custom_open fn
open = custom_open
Implicit here (and I didn't do research so it could be wrong) is that open('bla') is just calling out to file.__init__('bla'), so be careful there.
edit: You might also want to make sure you're overriding other methods on file, like flush or anything else that would cause Python to touch your disk.

How to save lists in python

I have a list including 4000 elements in python which each of its elements is an object of following class with several values.
class Point:
def __init__(self):
self.coords = []
self.IP=[]
self.BW=20
self.status='M'
def __repr__(self):
return str(self.coords)
I do not know how to save this list for future uses.
I have tried to save it by open a file and write() function, but this is not what I want.
I want to save it and import it in next program, like what we do in MATLAB that we can save a variable and import it in future
pickle is a good choice:
import pickle
with open("output.bin", "wb") as output:
pickle.dump(yourList, output)
and symmetric:
import pickle
with open("output.bin", "rb") as data:
yourList = pickle.load(data)
It is a good choice because it is included with the standard library, it can serialize almost any Python object without effort and has a good implementation, although the output is not human readable. Please note that you should use pickle only for your personal scripts, since it will happily load anything it receives, including malicious code: I would not recommend it for production or released projects.
This might be an option:
f = open('foo', 'wb')
np.save(f, my_list)
for loading then use
data = np.load(open('foo'))
if 'b' is not present in 'wb' then the program gives an error:
TypeError: write() argument must be str, not bytes
"b" for binary makes the difference.
Since you say Matlab, numpy should be an option.
f = open('foo', 'w')
np.save(f, my_list)
# later
data = np.load(open('foo'))
Of course, it'll return an array, not a list, but you can coerce it if you really want an array...