first working prototype
This commit is contained in:
29
client.py
Normal file
29
client.py
Normal file
@ -0,0 +1,29 @@
|
||||
import requests
|
||||
import json
|
||||
|
||||
|
||||
class Client:
|
||||
|
||||
def __init__(self, host="127.0.0.1", port=8080):
|
||||
self.host = host
|
||||
self.port = port
|
||||
self.session = requests.Session()
|
||||
|
||||
def add_row(self, **kwargs):
|
||||
addr = f"http://{self.host}:{self.port}/"
|
||||
resp = self.session.patch(addr, json=kwargs)
|
||||
resp.raise_for_status()
|
||||
return ResponseWrapper(resp)
|
||||
|
||||
|
||||
|
||||
class ResponseWrapper:
|
||||
|
||||
def __init__(self, resp):
|
||||
self.resp = resp
|
||||
|
||||
def __repr__(self):
|
||||
return self.resp.text
|
||||
|
||||
|
||||
|
4
hacks/__init__.py
Normal file
4
hacks/__init__.py
Normal file
@ -0,0 +1,4 @@
|
||||
|
||||
from . import patch_st_cp_stop
|
||||
|
||||
|
21
hacks/patch_st_cp_stop.py
Normal file
21
hacks/patch_st_cp_stop.py
Normal file
@ -0,0 +1,21 @@
|
||||
"""
|
||||
Monkey patch the streamlit server to stop cherrypy upon its own stop
|
||||
"""
|
||||
|
||||
|
||||
import cherrypy
|
||||
from streamlit.server.server import Server
|
||||
|
||||
|
||||
old_fn = Server._on_stopped
|
||||
|
||||
def new_fn(*args, **kwargs):
|
||||
print("exit cherrypy")
|
||||
cherrypy.engine.exit()
|
||||
print("exit streamlit")
|
||||
return old_fn(*args, **kwargs)
|
||||
|
||||
Server._on_stopped = new_fn
|
||||
|
||||
|
||||
|
58
restapi.py
Normal file
58
restapi.py
Normal file
@ -0,0 +1,58 @@
|
||||
from threading import Thread
|
||||
import json
|
||||
|
||||
import cherrypy as cp
|
||||
|
||||
from utils.df_utils import DateFrameHolder
|
||||
from utils.st_utils import rerun
|
||||
|
||||
|
||||
@cp.expose
|
||||
class TableAPI:
|
||||
|
||||
def __init__(self):
|
||||
self.dfh = DateFrameHolder()
|
||||
self.sid = None
|
||||
self.changed = True
|
||||
|
||||
@property
|
||||
def data(self):
|
||||
self.changed = False
|
||||
return self.dfh.df
|
||||
|
||||
@data.setter
|
||||
def data(self, df):
|
||||
self.dfh.df = df
|
||||
|
||||
@cp.tools.json_in()
|
||||
def PATCH(self, **kwargs):
|
||||
kwargs = kwargs or cp.request.json
|
||||
self.dfh.append(kwargs)
|
||||
self.changed = True
|
||||
rerun(self.sid)
|
||||
return str(self.dfh.df)
|
||||
|
||||
|
||||
|
||||
# creating instances here allows to use TableAPI etc. as singletons
|
||||
|
||||
print(">>> start TableAPI")
|
||||
|
||||
api = TableAPI()
|
||||
|
||||
conf = {
|
||||
"/": {
|
||||
"request.dispatch": cp.dispatch.MethodDispatcher(),
|
||||
"tools.sessions.on": True,
|
||||
"tools.response_headers.on": True,
|
||||
"tools.response_headers.headers": [("Content-Type", "text/plain")],
|
||||
}
|
||||
}
|
||||
|
||||
args = (api, "/", conf)
|
||||
|
||||
thread = Thread(target=cp.quickstart, args=args, daemon=True)
|
||||
thread.start()
|
||||
|
||||
|
||||
|
55
stand.py
Normal file
55
stand.py
Normal file
@ -0,0 +1,55 @@
|
||||
import streamlit as st
|
||||
from st_aggrid import AgGrid
|
||||
|
||||
import hacks
|
||||
|
||||
from restapi import api
|
||||
from utils.st_utils import get_session_id, rerun
|
||||
|
||||
|
||||
st.set_page_config(layout="wide")
|
||||
|
||||
|
||||
api.sid = get_session_id() # rest api needs current session ID to trigger the next rerun
|
||||
|
||||
changed = api.changed
|
||||
df = api.data
|
||||
|
||||
|
||||
|
||||
print(">>> start of streamlit run")
|
||||
|
||||
|
||||
response = AgGrid(
|
||||
df,
|
||||
|
||||
filter=True,
|
||||
editable=True,
|
||||
sortable=True,
|
||||
resizable=True,
|
||||
|
||||
# defaultWidth=5,
|
||||
fit_columns_on_grid_load=True,
|
||||
|
||||
reload_data=changed,
|
||||
key="stand"
|
||||
)
|
||||
|
||||
|
||||
new_df = response.get("data")#, df)
|
||||
if not new_df.equals(df) and not changed:
|
||||
api.data = new_df
|
||||
# print("old:")
|
||||
# print(df)
|
||||
# print("new:")
|
||||
# print(new_df)
|
||||
# print(">>> force rerun")
|
||||
# rerun()
|
||||
|
||||
#st.dataframe(df.astype(str))
|
||||
#st.dataframe(new_df.astype(str))
|
||||
|
||||
print(">>> end of streamlit run")
|
||||
|
||||
|
||||
|
0
utils/__init__.py
Normal file
0
utils/__init__.py
Normal file
15
utils/df_utils.py
Normal file
15
utils/df_utils.py
Normal file
@ -0,0 +1,15 @@
|
||||
import pandas as pd
|
||||
|
||||
|
||||
class DateFrameHolder:
|
||||
|
||||
def __init__(self, df=None):
|
||||
self.df = df or pd.DataFrame()
|
||||
# self.df = pd.DataFrame.from_records([dict(a=1, b=2, c=3)] * 4) #TODO: remove
|
||||
|
||||
def append(self, data):
|
||||
data = pd.DataFrame.from_records([data])
|
||||
self.df = pd.concat([self.df, data], ignore_index=True)
|
||||
|
||||
|
||||
|
21
utils/st_utils.py
Normal file
21
utils/st_utils.py
Normal file
@ -0,0 +1,21 @@
|
||||
import streamlit as st
|
||||
|
||||
|
||||
def rerun(session_id=None):
|
||||
if session_id is None:
|
||||
session_id = get_session_id()
|
||||
|
||||
server = st.server.server.Server.get_current()
|
||||
session = server._get_session_info(session_id).session
|
||||
|
||||
client_state = None
|
||||
session.request_rerun(client_state)
|
||||
|
||||
|
||||
|
||||
def get_session_id():
|
||||
ctx = st.scriptrunner.script_run_context.get_script_run_ctx()
|
||||
return ctx.session_id
|
||||
|
||||
|
||||
|
Reference in New Issue
Block a user