Implementation of "end_code_block" / using streamlit for notebook

I’d like to use streamlit as a “notebook”, where all (or most) of my code goes to the output in blocks (preceding the other streamlit output produced).

This is similar to what streamlit.echo already does, but putting a lot of code into indented blocks seems pretty verbose. So I implemented end_code_block as a separate function. Here’s an example using it:

from end_code_block import end_code_block as _____
import streamlit as st
import pandas as pd
_____(display=False)

message = 'hello world'
st.write(message)
_____()

df = pd.DataFrame({'x': [1, 2], 'y': [2, 3]})
df
_____()

st.write("bye")
_____()

(I imported the function as _____ because I think that looks nice separating the blocks.)

Then the output looks like this:

I’m posting here in case anyone else wants to use it, and also because I’m interested in what others think of this approach/workflow, and hearing about experiences trying to use streamlit like how you would use a Jupyter notebook.

I considered making a little package out of my code, but it’s only a few lines, so if you want it you’re probably better off copy/pasting into your own project. Or even better, I’d love if streamlit’s maintainers want to put something like this into streamlit itself.

I’ve put it in a Github repo here: https://github.com/dchudz/streamlit_end_code_block.

2 Likes

This is really awesome and innovative. One thing I thougth about is that you have open the source file multiple times. Could that be st.cached?

I’ve included it in the gallery at awesome-streamlit.org.

The file works when I run it on a standalone basis via streamlit run 'gallery\notebook_style\notebook_style.py'.

But not fully when run via the ‘exec’ statement that I use for the gallery and via streamlit run 'app.py'. The dataframe is missing.

I run the python file via the execstatement for historical reasons and because in that way I can easily include the Streamlit example files and keep them updated. But I will be moving away from that because some of the apps I would like to include are growing in size and would be nice to spread across multiple files.

The exec statement can be found here.

Thanks, glad you like it.

you have open the source file multiple times. Could that be st.cache d?

Or maybe a global constant.

But not fully when run via the ‘exec’ statement

Yeah. In my example I’m using stream’s “magic” to show the DataFrame when I just type df. My best guess is that your exec doesn’t play nice with streamlit’s implementation of magic.

Wow. This is some dark magic! :woman_mage:I wonder if this should be part of Streamlit itself… Amazing, @dchudz!!

2 Likes

Hi @dchudz

You’re right. The problem is Streamlit’s magic does not work when running the file via exec. So I changed dataframe to st.write(dataframe) and it works.

A global constant would not work (I believe) for two reasons. 1) It would be reread on each script rerun 2) Your code could be in multiple files.

Hi @dchudz

I’m still a little bit overwhelmed and impressed by your code. :+1:

How did you get the idea for _____() and the ideas on how to implement this? Have you seen the use of _____() and the implementation elsewhere? Did you get the inspiration from the implementation of st.write? Or was it just logical to you?

(I’m asking because I wan’t to learn).

… and from this I got two ideas for improving Streamlit

st.markdown with run_code argument?

The code

image

would output as

Maybe it could even be able to use a path or url to a markdown file like st.markdown(path="hello_world.md", run_code=True) or st.markdown(url="example.com/hello_world.md", run_code=True)

That would make it super simple to write blog posts with code and the output.

st.notebook widget

It could write a notebook st.notebook(path="hello_world.ipynb") or python code in notebook style

st.notebook("""
#%%
print("Hello World")

#%%
print("Hello again")
""")

The latter would output as

It’s very similar to streamlit.echo, so there wasn’t much else to do once I’d read the code for that.

Thanks Adrien! Streamlit is really nice.

Yeah, I’d love to see this in Streamlit itself. :slight_smile: (And I don’t think you’d be biting off much extra complexity, since you’ve already got streamlit.echo doing roughly the same thing.)

But I also love that given what Streamlit already built, it’s only ~15 lines of code for a user to add this. I think that’s a real testament to quality of your primitives.

Hi @Marc!

Nice ideas but I think some form of widget would be more clear than a flag in the markdown widget. Mostly because it wouldn’t be obvious what the behaviour will be with complex markdown files and most people will be fiddling with the markdown files instead of actually using Streamlit.

I think it is part of what makes Streamlit unique that it makes it possible and very easy to prototype dashboard apps. It would be nice to make Jupyter style apps also, but that’s something Jupyter already does well. I see it more as an extra because otherwise people will use Streamlit as a Jupyter replacement.

1 Like