20

Is there a way to run the command streamlit run APP_NAME.py from within a python script, that might look something like:

import streamlit
streamlit.run("APP_NAME.py")


As the project I'm working on needs to be cross-platform (and packaged), I can't safely rely on a call to os.system(...) or subprocess.

David
  • 537
  • 1
  • 3
  • 9

5 Answers5

22

Hopefully this works for others: I looked into the actual streamlit file in my python/conda bin, and it had these lines:

import re
import sys
from streamlit.cli import main

if __name__ == '__main__':
    sys.argv[0] = re.sub(r'(-script\.pyw|\.exe)?$', '', sys.argv[0])
    sys.exit(main())

From here, you can see that running streamlit run APP_NAME.py on the command line is the same (in python) as:

import sys
from streamlit import cli as stcli

if __name__ == '__main__':
    sys.argv = ["streamlit", "run", "APP_NAME.py"]
    sys.exit(stcli.main())

So I put that in another script, and then run that script to run the original app from python, and it seemed to work. I'm not sure how cross-platform this answer is though, as it still relies somewhat on command line args.

David
  • 537
  • 1
  • 3
  • 9
  • 2
    **Broken.** The `streamlit.cli` submodule no longer exists as of Streamlit 0.12.0: `ImportError: cannot import name 'cli' from 'streamlit' (/usr/lib/python3.10/site-packages/streamlit/__init__.py)`. Unstable upstream APIs is why we can't have stable StackOverflow answers. `` – Cecil Curry Sep 21 '22 at 05:32
  • 6
    **Update:** [the `streamlit.cli` submodule has been moved to `streamlit.web.cli`](https://stackoverflow.com/a/73523578/2809027). I can personally verify that the API otherwise appears to be identical. Gah! Why wouldn't Streamlit just add a simple alias from the latter to the former to preserve backward compatibility? That's *not* a good look in 2022, Streamlit – seriously. *Not cool.* – Cecil Curry Sep 21 '22 at 05:36
  • Bear in mind it may break again. The streamlit developers consider it internal. See here: https://discuss.streamlit.io/t/run-streamlit-from-pycharm/21624/3 – Rhubarb Aug 18 '23 at 14:37
8

You can run your script from python as python my_script.py:

import sys
from streamlit import cli as stcli
import streamlit
    
def main():
# Your streamlit code

if __name__ == '__main__':
    if streamlit._is_running_with_streamlit:
        main()
    else:
        sys.argv = ["streamlit", "run", sys.argv[0]]
        sys.exit(stcli.main())
Jiri Dobes
  • 89
  • 1
  • 2
  • While clever, violating privacy encapsulation by directly testing `streamlit._is_running_with_streamlit` is *not* a production-hardened solution. The Streamlit API moves rapidly. If this hasn't already broke, it probably will shortly. – Cecil Curry Sep 21 '22 at 05:13
  • @CecilCurry `streamlit._is_running_with_streamlit` doesn't work anymore now. Do you know the latest update for this? – Ming Jun Lim Oct 30 '22 at 08:55
  • You can query the port streamlit runs on and verify that the process matches streamlit: [How to check if a network port is open?](https://stackoverflow.com/questions/19196105/how-to-check-if-a-network-port-is-open) – Yaakov Bressler Nov 21 '22 at 20:01
  • Now there is a better solution: `from streamlit import runtime` and `runtime.exists()` instead of `streamlit._is_running_with_streamlit` – Alex Kosh Dec 11 '22 at 01:10
5

I prefer working with subprocess and it makes executing many scripts via another python script very easy.

The subprocess module allows you to spawn new processes, connect to their input/output/error pipes, and obtain their return codes. This module intends to replace several older modules and functions:

import subprocess
import os

process = subprocess.Popen(["streamlit", "run", os.path.join(
            'application', 'main', 'services', 'streamlit_app.py')])
Yaakov Bressler
  • 9,056
  • 2
  • 45
  • 69
Subir Verma
  • 393
  • 1
  • 3
  • 10
2

With the current streamlit version 1.21.0 the following works:

import streamlit.web.bootstrap
streamlit.web.bootstrap.run("APP_NAME.py", '', [], [])

Execute ?streamlit.web.bootstrap.run do get more info on the different options for streamlit.web.bootstrap.run. For example, you can provide some args to the script.

Jan
  • 405
  • 2
  • 12
  • This is not recommended by the developers as it uses an internal API (which already moved once). See here: https://github.com/streamlit/streamlit/issues/5471#issuecomment-1269076238 – Rhubarb Aug 18 '23 at 14:21
0

A workaround I am using is the following:

  1. Write the streamlit app to the temporary directory of the computer.
  2. Extecute the streamlit app.
  3. Remove the streamlit app again.
import os
import subprocess
import tempfile

def run_streamlit_app(app):
    # create a temporary directory
    temp_dir = tempfile.TemporaryDirectory()
    temp_file_path = os.path.join(temp_dir.name, 'app.py')
    
    # write the streamlit app code to a Python script in the temporary directory
    with open(temp_file_path, 'w') as f:
        f.write(app)
    
    # execute the streamlit app
    try:
        # execute the streamlit app
        subprocess.run(
            ["/opt/homebrew/Caskroom/miniforge/base/envs/machinelearning/bin/streamlit", "run", temp_file_path],
            stderr=subprocess.DEVNULL
        )
    except KeyboardInterrupt:
        pass
    
    # clean up the temporary directory when done
    temp_dir.cleanup()

where an example could look like the following:

app = """
import streamlit as st
import matplotlib.pyplot as plt
import numpy as np

arr = np.random.normal(1, 1, size=100)
fig, ax = plt.subplots()
ax.hist(arr, bins=20)

st.pyplot(fig)
"""
run_streamlit_app(app)
Ucl
  • 1
  • 1