I am using a module that when it outputs an error it just prints that error and continues the script, I would like to put that error into a variable, however because of this behavour I cant just do except Exception as e, so I'm looking for a way to put the previously printed line into a variable
note: I tried looking in the module for where it prints this, but couldnt find it
Well, it ain't pretty, but you could (hoping the write does not do anything funny) try to hijack sys.stdout.write() (or stderr, depending on where you script writes to).
This could be one way to do so, as ugly as it may be:
import sys
class Wrap:
def __init__(self):
self.last_line = None
self._next_line = ''
def write(self, text, *args, **kwargs):
sys.__stdout__.write(text, *args, **kwargs)
self._next_line += text
try:
self.last_line = self._next_line.split('\n')[-2]
self.next_line = self._next_line.split('\n')[-1]
except IndexError:
# We did not have \n yet and _next_line did not split
# into at least two items
pass
save_stdout = sys.stdout
sys.stdout = Wrap()
print('xxx\nzzz') # This was that function you wanted to call
last_line = sys.stdout.last_line
sys.stdout = save_stdout
print(last_line)
This will give you zzz as output. I.e. last line printed (w/o newline (re)added) while sys.stdout was our wrapper.
You can of course just write a function wrapper and use that to formalize the hack a bit.
Related
I'm working on an open source python library that uses a verbose_print command to log outputs in the console. Currently it looks like this:
def sys_write_flush(s):
""" Writes and flushes without delay a text in the console """
sys.stdout.write(s)
sys.stdout.flush()
def verbose_print(verbose, s):
""" Only prints s (with sys_write_flush) if verbose is True."""
if verbose:
sys_write_flush(s)
I proposed a change that looks like this:
def verbose_print(verbose, *args):
""" Prints everything passed except the first argument if verbose is True."""
if verbose:
print(*args)
Apart from the fact that it fails on Python 2 (bonus point for fixing this!), I thought that this would be better and more idiomatic. The advantages are, that you can treat verbose_print exactly like print, except that the first argument has to be True or False.
The repo owner replied with this message:
I should have documented this one, but basically the issue was that in
some consoles (and in the IPython notebook, at least at the time),
"print" commands get delayed, while stdout.flush are instantaneous, so
my method was better at providing feedback.
I would be against changing it to print unless it solves some known
issues.
Is this still a valid concern? Would print() followed by sys.stdout.flush() avoid the delay? Are there any better ways to write this?
Source
Quote from the docs:
print evaluates each expression in turn and writes the resulting
object to standard output.
Standard output is defined as the file object named stdout in the
built-in module sys. If no such object exists, or if it does not
have a write() method, a RuntimeError exception is raised.
According to this, print writes to sys.stdout, so, yes, doing a sys.stdout.flush() after printing will have the same effect as flushing after sys.stdout.write-ing.
The syntax print(*a) fails in Python 2 because print isn't a function, but a statement, and that fun(*stuff) construct is only applicable to functions.
In Python 3 print(*a) passes whatever a contains to the function print as separate arguments, but this is equal to passing a big string:
separator = ' '
print separator.join(map(str, iterable))
So, your code could look like this:
def verbose_print(verbose, *args):
""" Prints everything passed except the first argument if verbose is True."""
if verbose:
print " ".join(map(str, args))
sys.stdout.flush()
Although I don't see why this can be faster or more readable than the original.
I have the following code which for some reason is causing the Python GUI to crash at the line print:
urlstr = str(URLS)
a = urlstr.split('=', 2)
print('a=', a)
URLS is a URL generated from a dictionary, which is in turn created from the values of a series of text files. I am making a string from URLS then trying to split it at the second equals sign.
If I remove the print statement the code runs fine, but the conditional logic that 'a' is passed to does not produce a value.
Can anyone see what the issue is as I am really confused.
Thanks
I think you are using the IDLE Python shell and threads. Correct me if I am wrong.
Sometimes this causes Tkinter/the IDLE to crash.
Here is some code I wrote in 2008 to prevent the Python Shell from crashing when using threads.
## das muss in idlelib.PyShell in die letzten Zeilen der Klasse
## this must be copied to idlelib.PyShell into the last lines of the class
############################# adds by nicco kunzmann #########################
__nk___init__= __init__
def __init__(self, *args, **kw):
self.__nk___init__(*args, **kw)
self.__nk_writelist= []
self.__nk_act_act_write()
__nk_write= write
def write(self, *args):
self.__nk_writelist.append(args)
def __nk_act_act_write(self):
try:
while self.__nk_writelist:
args= self.__nk_writelist.pop(0)
try:
self.__nk_write(*args)
except:
traceback.print_exception(*sys.exc_info())
print args
finally:
self.text.after(1, self.__nk_act_act_write)
############################# adds by n.k. the end #########################
I use a internal library that prints a lot (one script could print 40000 lines in total), and I suppose it may have bad impact in performance. This is a library developed by another team in my company and do a lot of calculations, they print to debug errors (and I know this is not a good habit but it's too late because of 100 scripts already on production)
and I'm developing a script that uses 100 scripts to produce the result.
How can I decide to turn all this print off ?
I'm not asking how to print these lines to file, but completely omit it
Replace sys.stdout with an object that eats the output:
import sys
class Null:
def write(self, text):
pass
def flush(self):
pass
print "One" # This gets output OK
old_stdout = sys.stdout
sys.stdout = Null()
print "Two" # This disappears
sys.stdout = old_stdout
print "Three" # Output, back to normal
The best way is to simply remove the print statements as there
is no overhead whatsoever.
Alternatively, you can redirect the output to /dev/null, which will
effectively remove the I/O overhead but will not remove the syscall.
To spare the syscall you can replace sys.stdout with a Writer which does nothing.
For example:
class NullWriter():
def write(self, s): pass
sys.stdout = NullWriter()
Apparently, this has been asked and solved before. Also here.
In case you're using python 3, you can overload the print function as
seen in this answer:
def print(*args, **kwargs):
pass
I want to automatically indent the next line of a console app but the user needs to be able to remove it. sys.stdout.write and print make undeletable characters and I can't write to sys.stdin (as far as I know). I'm essentially trying to get smart indenting but I can only nest deeper and deeper. Any ideas on how to climb back out?
Edit: I should have noted that this is part of a Windows program that uses IronPython. While I could do something much fancier (and might in the future), I am hoping to quickly get a reasonably pleasant experience with very little effort as a starting point.
The cmd module provides a very simple interface for creating a command line interface to your program. It might not be able to put some buffer characters in front of the next line but if you're looking for an obvious way to let your users know that the command has returned, it can provide a shell-like prompt at the beginning of each line. If you already have functions defined for your program, integrating them into a processor would be a matter of writing a handler that access the function:
import cmd
import math
def findHpyot(length, height):
return math.sqrt(length **2 + height **2)
class MathProcessor(cmd.Cmd):
prompt = "Math>"
def do_hypot(self, line):
x = raw_input("Length:")
y = raw_input("Height:")
if x and y:
try:
hypot = findHypot(float(x), float(y))
print "Hypot:: %.2f" %hypot
except ValueError:
print "Length and Height must be numbers"
def do_EOF(self, line):
return True
def do_exit(self, line):
return True
def do_quit(self, line):
return True
if __name__ == "__main__":
cmdProcessor = MathProcessor()
cmdProcessor.cmdloop()
Things to consider when writing an interactive shell using cmd
The name after do_ is the command that your users will use so that in this example, the available commands will be hypot, exit, quit, and help.
Without overriding do_help, calling help will give you a list of available commands
Any call that you want to quit the program should return True
If you want to process entries from the function call, say you wanted to be able to handle a call like "hypot 3 4" you can use the local line variable in the function call
In my python code I have this line:
try:
result = eval(command, self.globals, self.locals)
except SyntaxError:
exec(command, self.globals, self.locals)
The command variable can be any string. Hence the python debugger pdb may be started in eval/exec and still be active when eval/exec is returning. What I want to do is make sure normal program execution is resumed when returning from eval/exec. To just give you an idea, this is approximately the behavior that I want:
try:
result = eval(command, self.globals, self.locals)
try: self.globals['pdb'].run('continue')
except: pass
except SyntaxError:
exec(command, self.globals, self.locals)
try: self.globals['pdb'].run('continue')
except: pass
However the try line is shown in the debugger before it is executed, but I dont want the debugger to show my code at all. Also it doesn't really work... The reason i repeat code is to minimize debugging in my code, else I could just do it after the except block.
So how can I do this?
As a sidenote:
If you try to enter the following lines into the IPython or bpython interpreters you'll see that they have the same problem and you are able to step into their code.
import pdb
pdb.set_trace()
next
However if you do this in the standard cpython interpreter you are returned to the python prompt. The reason for this is obviously because the two former are implemented in python and the last one is not. But my wish is to get the same behavior even when all code is python.
While I'm somewhat concerned that you are eval/exec'ing a string that you don't control, I'll assume you've thought that bit through.
I think the simplest thing would be to persuade pdb to check the stack frame on each step and resume automatically when you return to the desired level. You can do that with a simple bit of hotfixing. In the code below I've simplified it down to a simple eval since all you are really asking is to have pdb resume automatically on return to a specific function. Call Pdb().resume_here() in the function that you don't want traced. N.B. the resumption is global and there's only one resumption point but I'm sure you can modify that if you wanted.
If you run the code then you'll enter the debugger in function foo() and you can then single step but as soon as you return to bar() the code continues automatically.
e.g.
import sys
from pdb import Pdb
def trace_dispatch(self, frame, event, arg):
if frame is self._resume_frame:
self.set_continue()
return
return self._original_trace_dispatch(frame, event, arg)
def resume_here(self):
Pdb._resume_frame = sys._getframe().f_back
# hotfix Pdb
Pdb._original_trace_dispatch = Pdb.trace_dispatch
Pdb.trace_dispatch = trace_dispatch
Pdb.resume_here = resume_here
Pdb._resume_frame = None
def foo():
import pdb
pdb.set_trace()
print("tracing...")
for i in range(3):
print(i)
def bar():
Pdb().resume_here()
exec("foo();print('done')")
print("returning")
bar()