Print into console terminal not into cell output of IPython Notebook - python

I would like to print into the terminal window that runs IPython Notebook and not into the cell output. Printing into cell output consumes more memory and slows down my system when I issue a substantial number of print calls. In essence, I would like this behaviour by design.
I have tried the following:
I tried a different permutations of print and sys.stdout.write calls
I looked at the IPython Notebook documentation here, here and here without help
I have tried using this as a workaround but it seems to be only working on Python 2.7

You have to redirect your output to the systems standard output device. This depends on your OS. On Mac that would be:
import sys
sys.stdout = open('/dev/stdout', 'w')
Type the above code in an IPython cell and evaluate it. Afterwards all output will show up in terminal.

On Windows, this can work:
import sys
sys.stdout = open(1, 'w')

In order to be able to switch form one to the other easily:
terminal_output = open('/dev/stdout', 'w')
print('this will show up in the IPython cell output')
print('this will show up in the terminal', file=terminal_output)
Similarly, terminal_error = open('/dev/stderr', 'w') can be used to send to the terminal stderr, without any conflict with the default behavior of sys.stderr (which is to print an error message in the IPython cell output).

Related

How to refresh/overwrite console output in python

I want to know how to refresh the console of my program as if it was just started. Let's say that my code consists of an infinite loop and it has multiple instances of the print() function within itself, I want, every time that loops returns to its start, all the new data whether there is some change or not to get outputted on the same place of the data that has been outputted the last time.
I have been reading about similar problems others have posted and the answers usually revolve around the idea of using \r, when I do that, however, it's always messy and the strings are either printed halfway or there are missing characters. On Replit there is a module called "replit" and there is a function there called clear() that basically performs what I need, but I don't seem to find it when I am using PyCharm, which means that it is perhaps something that works exclusively within the Replit environment. So I am asking, is there something similar in the standard python library that I can use? Thanks
You can use:
import os
command = 'cls' #for windows
os.system(command)
example:
print('hi')
os.system(command)
print('hi')
Output:
hi
For windows you need:
command = 'cls'
For all others it is:
command = 'clear'
To account for any OS you could use:
import os
def clearConsole():
command = 'clear'
if os.name in ('nt', 'dos'): # If computer is running windows use cls
command = 'cls'
os.system(command)
clearConsole()
There is nothing standard in Python to do it, because Python is not aware of whatever console you are using.
When you call print it is actually writing to a file called "standard output".
It can go to a console if you are running your program in a console (like windows cmd, Linux or Mac OS terminal app, or whatever PyCharm uses).
But it can also be redirected to a regular file by the user of your program.
So there is no standard way.
\r is "carriage return" character. On consoles that respect it, it will set your output position to the beginning of the current line, but will not erase any text already printed on that line (usually).
One way to print text in specific places on the screen is PyCurses.
It supports many consoles and figures out which one you are using automatically.
You can do something like this:
import curses
stdscr = curses.initscr()
stdscr.addstr(x, y, "my string")
By using the addstr isntead of print, you can choose the exact position the text will appear, with X and Y coordinates (first two parameters).
Read the documentation for more ways to manipulate text display with this library.

Printing the console to a log file is not reversible in Spyder for Python

I am using Spyder for Python and sometime I would like to print the console into a log file (in cases where the output is quite long) and sometimes I just want to have the output at the console. For this purpose I use the following construction in my Python files:
In the beginning of the file:
import sys
# specify if the output should be printed on a separate log file or on the console
printLogToFile = False
if printLogToFile == True:
#Specify output file for the logs
sys.stdout = open('C:/Users/User 1/logfile.txt', 'w')
At the end of the file:
# Close the log file if output is printed on a log file and not on the console
if printLogToFile == True:
sys.stdout.close()
sys.stdout = sys.__stdout__
Basically, whenever my boolean variable printLogToFile has the value False then everything is printed on the console as it should and whenever it has the value True everything is printed into the logfile. However, once I run just once the file with printLogToFile=True this can't be reversed any longer. Even when the variable has the value False it still prints everything into the log file and not onto the console. What is even more strange is that also for other Python files, that do not have any connection to this file, the console is not printed any longer onto the console. The only way to solve this problem is to close Spyder and restart it again.
Do you have any idea why this is happening and how to avoid this? I'd appreciate every comment.
The console in Spyder is an IPython console, not a plain Python console, so I think IPython is doing something with stdout that causes your approach to fail.
The docs for sys.__stdout__ say
It can also be used to restore the actual files to known working file
objects in case they have been overwritten with a broken object.
However, the preferred way to do this is to explicitly save the
previous stream before replacing it, and restore the saved object.
In other words, try:
if printLogToFile:
prev_stdout = sys.stdout
sys.stdout = open('C:/Users/User 1/logfile.txt', 'w')
# code that generates the output goes here
if printLogToFile:
sys.stdout.close()
sys.stdout = prev_stdout
As an alternative, based on this answer and this answer assuming Python >= 3.7, you can use contextlib and a with statement to selectively capture the output of some of your code. This seems to work for me in Spyder 4 and 5:
from contextlib import redirect_stdout, nullcontext
if printLogToFile:
f = open('myfile.txt', 'w')
cm = redirect_stdout(f)
else:
cm = nullcontext()
with cm:
# code that generates the output goes here
If you want to execute the whole of your Python script myscript.py and capture everything it outputs, it's probably easier to leave your script unmodified and call it from a wrapper script:
# put this in the same folder as myscript.py
from contextlib import redirect_stdout
with redirect_stdout(open('myfile.txt', 'w')):
import myscript
If you want anything more flexible than that, it's probably time to start using logging.

Replacing standard input with a string in python3 using jupyter

I am trying to replace the standard input by a previously defined string.
After browsing on stack overflow, I found several solutions (though mostly for python2).
The solution below for example was tested in ideone.com and seems to work, however when I tried to add it to my code in my jupyter notebook the redefinition of the standard input gets ignored.
Is this due to jupyter or some problem in my code, and how could I fix it ?
import io,sys
s = io.StringIO('Hello, world!')
sys.stdin = s
sys.__stdin__ = s
r = input()
print(r)
The short answer is that Jupyter notebook doesn't support stdin/stdout, so you can't rely on them in notebook code.
The longer answer is that stdin/stdout are implemented differently in Jupyter than in standard Python, owing to the particulars of how Jupyter accepts input/displays output. If you want something that will ask for user input if there's no input currently available, this would work:
import io,sys
# if sys.stdin is empty, the user will be prompted for input
# sys.stdin = io.StringIO('')
sys.stdin = io.StringIO('Hello world')
r = sys.stdin.readline()
if not r:
r = builtins.input()
print(r)
Reference
stdin/stdout is spoken of somewhat eliptically in the Jupyter/IPython docs. Here's a relevant direct quote, though, from the %reset magic docs:
Calling this magic from clients that do not implement standard input, such as the ipython notebook interface, will reset the namespace without confirmation.

Sending curses application's output to tty1

Goal
I'd like to make my curses Python application display its output on a Linux machine's first physical console (TTY1) by adding it to /etc/inittab, reloading init with telinit q and so on.
I'd like to avoid a hacky way of using IO redirection when starting it from /etc/inittab with:
1:2345:respawn:/path/to/app.py > /dev/tty1 < /dev/tty1
What I'm after is doing it natively from within my app, similar to the way getty does it, i.e. you use a command line argument to tell it on which TTY to listen to:
S0:2345:respawn:/sbin/getty -L ttyS1 115200 vt100
Example code
For simplicity, let's say I've written this very complex app that when invoked, prints some content using ncurses routines.
import curses
class CursesApp(object):
def __init__(self, stdscr):
self.stdscr = stdscr
# Code producing some output, accepting user input, etc.
# ...
curses.wrapper(CursesApp)
The code I already have does everything I need, except that it only shows its output on the terminal it's run from. When invoked from inittab without the hacky redirection I mentioned above, it works but there's no output on TTY1.
I know that init doesn't redirect input and output by itself, so that's expected.
How would I need to modify my existing code to send its output to the requested TTY instead of STDOUT?
PS. I'm not asking how to add support for command line arguments, I already have this but removed it from the code sample for brevity.
This is rather simple. Just open the terminal device once for input and once for output; then duplicate the input descriptor to the active process' file descriptor 0, and output descriptor over file descriptors 1 and 2. Then close the other handles to the TTY:
import os
import sys
with open('/dev/tty6', 'rb') as inf, open('/dev/tty6', 'wb') as outf:
os.dup2(inf.fileno(), 0)
os.dup2(outf.fileno(), 1)
os.dup2(outf.fileno(), 2)
I tested this with the cmd module running on TTY6:
import cmd
cmd.Cmd().cmdloop()
Works perfectly. With curses it is apparent from their looks that something is missing: TERM environment variable:
os.environ['TERM'] = 'linux'
Execute all these statements before even importing curses and it should work.

Duplicating terminal output from a Python subprocess

I'm working on a wrapper script for invocations to the Ninja c/c++ buildsystem, the script is in python and one thing it should do is to log the output from Ninja and the underlying compiler but without supressing standard output.
The part that gives me trouble is that Ninja seems to detect that it is writing to a terminal or not, so simply catching the output and sending it to standard output ends up changing it (most notably, Ninja does not fill the screen with lists of warning and errorless buildfiles but removes the line of the last successfully built translation unit as a new one comes in). Is there any way to let Ninja write to the terminal, while still capturing its output? The writing to the terminal should happen as the Ninja subprocess runs, but the capturing of said output may wait until the subprocess has completed.
pty.spawn() allows you to log output to a file while hoodwinking Ninja subprocess into thinking that it works with a terminal (tty):
import os
import pty
logfile = open('logfile', 'wb')
def read(fd):
data = os.read(fd, 1024)
logfile.write(data)
return data
pty.spawn("ninja", read)

Categories