# Cannot print the terminal output in Streamlit?

Hi guys,

I’m trying to get a terminal output to be printed in Streamlit. I tried various codes including this one

import searchconsole
account = searchconsole.authenticate(client_config="GSCTatieLouCredentials.json", serialize='credentials.json', flow="console")
st.write(account)


but nothing seems to work - See screenshot below:

Any idea on how to print in Streamlit?

Thanks,
Charly

Hello @Charly_Wargnier,

One solution would be to redirect stdout/stderr to st.write (or anything you want).

Here’s a quick example for stdout:

from contextlib import contextmanager, redirect_stdout
from io import StringIO
from time import sleep
import streamlit as st

@contextmanager
def st_capture(output_func):
with StringIO() as stdout, redirect_stdout(stdout):
old_write = stdout.write

def new_write(string):
ret = old_write(string)
output_func(stdout.getvalue())
return ret

stdout.write = new_write
yield

output = st.empty()
with st_capture(output.code):
print("Hello")
sleep(1)
print("World")

output = st.empty()
with st_capture(output.info):
print("Goodbye")
sleep(1)
print("World")


1 Like

Thank you Synode!

Please report this bug at https://github.com/streamlit/streamlit/issues.


See error below:

(venv) C:\Users\Charly\Desktop\StreamForecast>streamlit run PrintToTerminalSynode.py
Traceback (most recent call last):
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\streamlit\server\server.py", line 412, in _loop_coroutine
on_started(self)
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\streamlit\bootstrap.py", line 135, in _on_server_start
_print_url(server.is_running_hello)
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\streamlit\bootstrap.py", line 210, in _print_url
click.secho("")
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\click\termui.py", line 548, in secho
return echo(message, file=file, nl=nl, err=err, color=color)
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\click\utils.py", line 272, in echo
file.write(message)
File "C:\Users\Charly\Desktop\StreamForecast\PrintToTerminalSynode.py", line 13, in new_write
output_func(stdout.getvalue())
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\streamlit\elements\markdown.py", line 137, in code
return dg._enqueue("markdown", code_proto)  # type: ignore
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\streamlit\delta_generator.py", line 335, in _enqueue
_enqueue_message(msg)
File "c:\users\charly\desktop\streamforecast\venv\lib\site-packages\streamlit\delta_generator.py", line 714, in _enqueue_message
raise NoSessionContext()
streamlit.errors.NoSessionContext
2020-10-25 10:28:54.239
Please report this bug at https://github.com/streamlit/streamlit/issues.


Is this expected?

Thanks,
Charly

Hmm, not quite

It was literally your code pasted verbatim in a Venv folder!

Hmm, indeed. I’ve implemented that while streamlit was already running. I didn’t run it from scratch though. I’ll fix that a little bit later today

1 Like

Thanks Synode. I actually found a workaround for my issue, although I (and others I’m sure :)) would still be keen to see the above code working

Charly

Hi @synode,

It looks like I may have spoken too fast! The workaround I found earlier doesn’t quite work, issue logged here:

I believe that being able to print the console’s output to Streamlit would likely fix the issue. As you can see in the screenshot below, users would need to click on the URL in the console for the app to work:

Instead, I either get the Errno 98 issue (issue above) or nothing happens… whereas ideally users should be redirected to Google’s consent screen.

Thanks,
Charly

Alright, new version. Tell me if it works in your case

EDIT: removed output = st.empty(). Now you just have to put streamlit’s function name as parameter.

from contextlib import contextmanager
from io import StringIO
import streamlit as st
import sys

@contextmanager
def st_redirect(src, dst):
placeholder = st.empty()
output_func = getattr(placeholder, dst)

with StringIO() as buffer:
old_write = src.write

def new_write(b):
buffer.write(b)
output_func(buffer.getvalue())
else:
old_write(b)

try:
src.write = new_write
yield
finally:
src.write = old_write

@contextmanager
def st_stdout(dst):
with st_redirect(sys.stdout, dst):
yield

@contextmanager
def st_stderr(dst):
with st_redirect(sys.stderr, dst):
yield

with st_stdout("code"):
print("Prints as st.code()")

with st_stdout("info"):
print("Prints as st.info()")

with st_stdout("markdown"):
print("Prints as st.markdown()")

with st_stdout("success"), st_stderr("error"):
print("You can print regular success messages")
print("And you can redirect errors as well at the same time", file=sys.stderr)


1 Like

Thanks! Will try now!

Hi Synode.

Thanks again for taking the time to write this code, much appreciated!

For some reason, I still can’t get the message from my terminal printed.

I’ve put together a little mock-up which may shed a bit more light on what I’m after

• #1 Your code, which I pasted at the end of my script.
• #2 the terminal text I want printed
• #3 the terminal text doesn’t print in Streamlit
• #4 FYI the Google Consent Screen which appears locally gets blocked when deployed in Heroku or Streamlit Sharing - This is the main reason why I want the terminal message to be printed

Note that I’ve pasted your code in my script without any modifications - Maybe I should have added something to it?

Charly

Love those mock-ups

My guess is that your google API does some sort of print (which uses sys.stdout internally).
What my proof-of-concept does is redirect sys.stdout to a streamlit function of your choice.

To make it work in your case, you have to put your functions that print messages in your terminal inside that kind of code block:

with st_stdout("info"):
# Inside this block, every function that prints to your terminal
# will have their output redirected to output.info(), a streamlit function.


I guess that the function which prints to your terminal is searchconsole.authenticate(), right? You’d do something like this:

with st_stdout("info"):
searchconsole.authenticate(client_config="GSCTatieLouCredentials.json", serialize='credentials.json', flow="console")

1 Like

Small notice, I’ve edited my two last replies. I’ve updated the code to avoid using that output = st.empty() in your code.

1 Like

Thanks Synode! It works great!

On a rather cosmetic note, I was wondering whether the displayed text could be “wrapped”?

Reason being: The URL that is retrieved from the terminal is very long and far overflows the box’s bounds, if that makes sense.

Thanks,
Charly

The only streamlit element that could work in your case is “code” I guess:

with st_stdout("code"):