Giter Club home page Giter Club logo

hydralit's Introduction

Hydralit hydra

The Hydralit package is a wrapping and template project to combine multiple independant (or somewhat dependant) Streamlit applications into a multi-page application.

Currently the project implements a host application HydraApp and each child application simply needs to be either a class deriving from the HydraHeadApp class and implementing a single, simple method, run() for maximum profit, or you can use a Flask style decorator on your functions to add them directly as seperate Streamlit pages.

When converting existing applications, you can effectively put all the existing code inside the run() method and create a wrapper class deriving from HydraHeadApp or put a decorator over the function. Then you create the parent app as an instance of HydraApp, add your child apps to it (see example secure_app.py) and with only a few lines of code everything will magically come together.


Version 1.0.14 fixes session state refactor performed by Streamlit, maybe after changing it 10 times they'll settle on a way forward, or they're just trying to constantly break the Hydralit package, wtf knows.

  • Now compatible with Streamlit >=1.12, thanks to the tireless efforts of saikumarmk

Version 1.0.13 fixes the long standing stupidty of Streamlit constantly changing the method name of the session context manager, now works with Streamlit 1.9.x and above.

  • Added the ability to disable to use of the app loader within the constructor.

Version 1.0.12 fixes an edge case when installing with Streamlit for the first time.


Hydralit now fully supports all versions of Streamlit, including 1.4.0, despite the odd changes made in version 1.4.0 that completely broke Hydralit.


Hydralit >=1.0.3 now requires a minimum version of Streamlit >=0.86.x to fully support the recently migrated beta containers, if using Streamlit <=0.85.x please continue to use Hydralit <=1.0.2


Installation

Hydralit can be installed from PyPI:

pip install -U hydralit

Lightning Example

#when we import hydralit, we automatically get all of Streamlit
import hydralit as hy

app = hy.HydraApp(title='Simple Multi-Page App')

@app.addapp()
def my_home():
 hy.info('Hello from app1')

@app.addapp()
def app2():
 hy.info('Hello from app 2')


#Run the whole lot, we get navbar, state management and app isolation, all with this tiny amount of work.
app.run()

This tiny amount of code creates a menu and pages that render when the target function is called by selecting it from the menu.

Quick Example

Latest features (version 1.0.11)

  • Fully supports all versions of Streamlit, including 1.4.0 (big thanks to oggers for some amazing support!).
  • Fixed the missing error handling bug, now all exceptions are raised to be handled however the user chooses instead of capturing and displaying an image. (big thanks to rambam613 for finding and fixing this bug, very nice!).
  • Can completely customise the Home and Logout menu entries, title and icon data from the add_app entry will be used for these items now as well as the existing.

Navbar

  • Cleaned up the formatting when running in sticky and hiding Streamlit headers and footers, yes, they will come back now when using the navbar.
  • Removed the background effort for all loader animations (everyone hated this).
  • Smaller, sleeker navbar, including a much nicer non-animated mode.

Navbar

  • Full offline support for Font Awesome and Bootstrap icons for navbar entries, as well as all emojis.
  • Improved performance with some refactoring of the session and transition code, apps load faster now.


<br

Version 1.0.10 features

  • Added Flask like decorators to convert any function into a child app (see example below)
  • Can set auto login with guest account when using a secure app
  • Support for a non-secure app in a secure app (like a signup app)
  • Full integration with the Hydralit Navbar that now supports complex nav!
  • some bug fixes where app to app redirect was inconsistant
  • Banners
  • Compression behind download button
  • Hydralit Navbar
  • Can turn off the navbar animation now! (must be using Hydralit_components >=1.0.4)

NOTE

Due to the Streamlit execution model, the ability to use internal nav links from a child app is one-shot when using the navbar. This means that the internal link will redirect to the child, however if a script rerun request is made within the child app (changing the value of a widget for example), the nav will bounce back to the calling app. You can disable the navbar and the Streamlit core components nav menu will appear and the internal links will work as expected.

Complex and sticky nav with no Streamlit markers is as easy as a couple of parameters in the Hydralit constructor.

app = HydraApp(title='Secure Hydralit Data Explorer',favicon="๐Ÿ™",hide_streamlit_markers=True,use_navbar=True, navbar_sticky=True)

Now powered by Hydralit Components.

The Hydralit Navbar is fully integrated, theme aware and animated (you can turn it off if you like), just add your child apps and go, the navbar will appear automatically.

Navbar - Responsive, theme aware and animated.

Quick Example

Spinners and Loaders

Out of the box you get a nice loader/spinner when navigating between apps/pages. You can also create your own loader app and completely customise every part of how it looks and when it loads, even creating different effects depending on the target application. See the Hydralit secure example code to see what is possible.

HyLoaders HyLoaders HyLoaders

Quick Start

If you have some functions and want them to run like seperate pages, you can quickly get going with a Flask style decorator over your functions.

#when we import hydralit, we automatically get all of Streamlit
import hydralit as hy

app = hy.HydraApp(title='Simple Multi-Page App')

@app.addapp(is_home=True)
def my_home():
 hy.info('Hello from Home!')

@app.addapp()
def app2():
 hy.info('Hello from app 2')

@app.addapp(title='The Best', icon="๐Ÿฅฐ")
def app3():
 hy.info('Hello from app 3, A.K.A, The Best ๐Ÿฅฐ')

#Run the whole lot, we get navbar, state management and app isolation, all with this tiny amount of work.
app.run()

This tiny amount of code creates a nice custom multi-page app as below.

Quick Example

Examples

You can try it out by running the two sample applications with their children that are located in the hydralit-example repository.

hydralit_example> pip install -r requirements.txt

hydralit_example> streamlit run secure.app

Converting existing applications

This code sample comes directly from the Streamlit example data explorer

import streamlit as st
import pandas as pd
import numpy as np

st.title('Uber pickups in NYC')

DATE_COLUMN = 'date/time'
DATA_URL = ('https://s3-us-west-2.amazonaws.com/'
            'streamlit-demo-data/uber-raw-data-sep14.csv.gz')

@st.cache
def load_data(nrows):
    data = pd.read_csv(DATA_URL, nrows=nrows)
    lowercase = lambda x: str(x).lower()
    data.rename(lowercase, axis='columns', inplace=True)
    data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
    return data

data_load_state = st.text('Loading data...')
data = load_data(10000)
data_load_state.text("Done! (using st.cache)")

if st.checkbox('Show raw data'):
    st.subheader('Raw data')
    st.write(data)

st.subheader('Number of pickups by hour')
hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0,24))[0]
st.bar_chart(hist_values)

# Some number in the range 0-23
hour_to_filter = st.slider('hour', 0, 23, 17)
filtered_data = data[data[DATE_COLUMN].dt.hour == hour_to_filter]

st.subheader('Map of all pickups at %s:00' % hour_to_filter)
st.map(filtered_data)

Let's also use a simple application to combine with the demo above.

import streamlit as st
import numpy as np
import pandas as pd
from data.create_data import create_table

def app():
    st.title('Small Application with a table and chart.')

    st.write("See `apps/simple.py` to know how to use it.")

    st.markdown("### Plot")
    df = create_table()

    st.line_chart(df)

You can easily convert these apps to be used within Hydralit by simply wrapping each in a class derived from HydraHeadApp within Hydralit and putting all the code in the run() method.

For the above Streamlit demo application, this means all that is needed is a slight modification, we create a file sample_app.py and add;

import streamlit as st
import pandas as pd
import numpy as np

#add an import to Hydralit
from hydralit import HydraHeadApp

#create a wrapper class
class MySampleApp(HydraHeadApp):

#wrap all your code in this method and you should be done
    def run(self):
        #-------------------existing untouched code------------------------------------------
        st.title('Uber pickups in NYC')

        DATE_COLUMN = 'date/time'
        DATA_URL = ('https://s3-us-west-2.amazonaws.com/'
                    'streamlit-demo-data/uber-raw-data-sep14.csv.gz')

        @st.cache
        def load_data(nrows):
            data = pd.read_csv(DATA_URL, nrows=nrows)
            lowercase = lambda x: str(x).lower()
            data.rename(lowercase, axis='columns', inplace=True)
            data[DATE_COLUMN] = pd.to_datetime(data[DATE_COLUMN])
            return data

        data_load_state = st.text('Loading data...')
        data = load_data(10000)
        data_load_state.text("Done! (using st.cache)")

        if st.checkbox('Show raw data'):
            st.subheader('Raw data')
            st.write(data)

        st.subheader('Number of pickups by hour')
        hist_values = np.histogram(data[DATE_COLUMN].dt.hour, bins=24, range=(0,24))[0]
        st.bar_chart(hist_values)

        # Some number in the range 0-23
        hour_to_filter = st.slider('hour', 0, 23, 17)
        filtered_data = data[data[DATE_COLUMN].dt.hour == hour_to_filter]

        st.subheader('Map of all pickups at %s:00' % hour_to_filter)
        st.map(filtered_data)
        #-------------------existing untouched code------------------------------------------

For the other small application, again we can convert this very easily by wrapping in a class derived from HydraHeadApp from Hydralit and putting all the code in the run() method, we create a file small_app.py and add;

import streamlit as st
import numpy as np
import pandas as pd
from data.create_data import create_table

#add an import to Hydralit
from hydralit import HydraHeadApp

#create a wrapper class
class MySmallApp(HydraHeadApp):

#wrap all your code in this method and you should be done
    def run(self):
        #-------------------existing untouched code------------------------------------------
        st.title('Small Application with a table and chart.')

        st.markdown("### Plot")
        df = create_table()

        st.line_chart(df)

These are is now ready to be used within a Hydralit application. We just need to create a simple host application that derives from the HydraApp class in Hydralit, add the children and we are done! we create a file host_app.py and add;

from hydralit import HydraApp
import streamlit as st
from sample_app import MySampleApp
from small_app import MySmallApp


if __name__ == '__main__':

    #this is the host application, we add children to it and that's it!
    app = HydraApp(title='Sample Hydralit App',favicon="๐Ÿ™")
  
    #add all your application classes here
    app.add_app("Small App", icon="๐Ÿ ", app=MySmallApp())
    app.add_app("Sample App",icon="๐Ÿ”Š", app=MySampleApp())

    #run the whole lot
    app.run()

Or you could use the decorator method shown in the Lightning example and simply wrap your functions, both ways work, you can get access to more controls with the class method as the template class allows access to the Hydralit internal state for access and navigation information.

This super simple example is made of 3 files.

hydralit sample project
โ”‚   host_app.py
โ”‚   small_app.py
โ”‚   sample_app.py

Run this sample

hydralit sample project> pip install hydralit

hydralit sample project> streamlit run host.app

Examples

The code for a host application that is secured with a login app is shown below, the entire example is located in the hydralit-example repository.

from hydralit import HydraApp
import streamlit as st
import apps


if __name__ == '__main__':
    over_theme = {'txc_inactive': '#FFFFFF'}
    #this is the host application, we add children to it and that's it!
    app = HydraApp(
        title='Secure Hydralit Data Explorer',
        favicon="๐Ÿ™",
        hide_streamlit_markers=False,
        #add a nice banner, this banner has been defined as 5 sections with spacing defined by the banner_spacing array below.
        use_banner_images=["./resources/hydra.png",None,{'header':"<h1 style='text-align:center;padding: 0px 0px;color:black;font-size:200%;'>Secure Hydralit Explorer</h1><br>"},None,"./resources/lock.png"], 
        banner_spacing=[5,30,60,30,5],
        use_navbar=True, 
        navbar_sticky=False,
        navbar_theme=over_theme
    )

    #Home button will be in the middle of the nav list now
    app.add_app("Home", icon="๐Ÿ ", app=apps.HomeApp(title='Home'),is_home=True)

    #add all your application classes here
    app.add_app("Cheat Sheet", icon="๐Ÿ“š", app=apps.CheatApp(title="Cheat Sheet"))
    app.add_app("Sequency Denoising",icon="๐Ÿ”Š", app=apps.WalshApp(title="Sequency Denoising"))
    app.add_app("Sequency (Secure)",icon="๐Ÿ”Š๐Ÿ”’", app=apps.WalshAppSecure(title="Sequency (Secure)"))
    app.add_app("Solar Mach", icon="๐Ÿ›ฐ๏ธ", app=apps.SolarMach(title="Solar Mach"))
    app.add_app("Spacy NLP", icon="โŒจ๏ธ", app=apps.SpacyNLP(title="Spacy NLP"))
    app.add_app("Uber Pickups", icon="๐Ÿš–", app=apps.UberNYC(title="Uber Pickups"))
    app.add_app("Solar Mach", icon="๐Ÿ›ฐ๏ธ", app=apps.SolarMach(title="Solar Mach"))

    #we have added a sign-up app to demonstrate the ability to run an unsecure app
    #only 1 unsecure app is allowed
    app.add_app("Signup", icon="๐Ÿ›ฐ๏ธ", app=apps.SignUpApp(title='Signup'), is_unsecure=True)

    #we want to have secure access for this HydraApp, so we provide a login application
    #optional logout label, can be blank for something nicer!
    app.add_app("Login", apps.LoginApp(title='Login'),is_login=True) 

    #specify a custom loading app for a custom transition between apps, this includes a nice custom spinner
    app.add_loader_app(apps.MyLoadingApp(delay=5))
    #app.add_loader_app(apps.QuickLoaderApp())

    #we can inject a method to be called everytime a user logs out
    @app.logout_callback
    def mylogout_cb():
        print('I was called from Hydralit at logout!')

    #we can inject a method to be called everytime a user logs in
    @app.login_callback
    def mylogin_cb():
        print('I was called from Hydralit at login!')

    #if we want to auto login a guest but still have a secure app, we can assign a guest account and go straight in
    app.enable_guest_access()

    #--------------------------------------------------------------------------------------------------------------------
    #if the menu is looking shit, use some sections
    #check user access level to determine what should be shown on the menu
    user_access_level, username = app.check_access()

    # If the menu is cluttered, just rearrange it into sections!
    # completely optional, but if you have too many entries, you can make it nicer by using accordian menus
    if user_access_level > 1:
        complex_nav = {
            'Home': ['Home'],
            'Intro ๐Ÿ†': ['Cheat Sheet',"Solar Mach"],
            'Hotstepper ๐Ÿ”ฅ': ["Sequency Denoising","Sequency (Secure)"],
            'Clustering': ["Uber Pickups"],
            'NLP': ["Spacy NLP"],
        }
    elif user_access_level == 1:
        complex_nav = {
            'Home': ['Home'],
            'Intro ๐Ÿ†': ['Cheat Sheet',"Solar Mach"],
            'Hotstepper ๐Ÿ”ฅ': ["Sequency Denoising"],
            'Clustering': ["Uber Pickups"],
            'NLP': ["Spacy NLP"],
        }
    else:
        complex_nav = {
            'Home': ['Home'],
        }

  
    #and finally just the entire app and all the children.
    app.run(complex_nav)

    #(DEBUG) print user movements and current login details used by Hydralit
    #---------------------------------------------------------------------
    user_access_level, username = app.check_access()
    prev_app, curr_app = app.get_nav_transition()
    print(prev_app,'- >', curr_app)
    print(int(user_access_level),'- >', username)
    #---------------------------------------------------------------------

You can try it out by running the two sample applications with their children that are located in the hydralit-example repository.

hydralit_example> pip install -r requirements.txt

hydralit_example> streamlit run secure.app

hydralit's People

Contributors

calculusentropy avatar patarimi avatar saikumarmk avatar tanglespace avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar

hydralit's Issues

show streamlit markers doesn't seem to work

In this toy application, i expect to see the Streamlit hamburger icon in the top right part of the page and the watermark at the bottom, but I don't.

hydralit==1.0.10
hydralit-components==1.0.6
streamlit==1.1.0

import hydralit as hy

app = hy.HydraApp(title='Simple Multi-Page App', favicon="๐Ÿ™",hide_streamlit_markers=False,use_navbar=True, navbar_sticky=True, use_banner_images="./resources/AI4booklovers.png")

@app.addapp()
def my_home():
 hy.info('Hello from app1')

@app.addapp()
def app2():
 hy.info('Hello from app 2')


#Run the whole lot, we get navbar, state management and app isolation, all with this tiny amount of work.
app.run()

Screen Shot 2021-11-11 at 2 06 14 PM

making cookie based login work.

So I was trying to hold a JWT token in cookie when login button is pressed.

app.py

import hydralit as hy
import streamlit as st
from hydralit_components import CookieManager
from login import LoginApp

cookie_manager = CookieManager()
app = hy.HydraApp(title='test', favicon="๐Ÿ™", hide_streamlit_markers=True,
                  allow_url_nav=True, sidebar_state="expanded",
                  layout='wide'
                  )

app.add_app("Login", LoginApp(cookie_manager=cookie_manager), is_login=True, logout_label="Logout")

@app.logout_callback
def mylogout_cb():
    cookie_manager.delete('user_data')
    print('I was called from Hydralit at logout!')

@app.login_callback
def mylogin_cb():
    print('I was called from Hydralit at login!')

login.py

class LoginApp(HydraHeadApp):
    """
    This is an example login application to be used to secure access within a HydraApp streamlit application.
    This application implementation uses the allow_access session variable and uses the do_redirect method if the login check is successful.

    """

    def __init__(self, cookie_manager, title='', **kwargs):
        self.__dict__.update(kwargs)
        self.title = title
        self.cookie_manager = cookie_manager

    def _check_cookie_login(self) -> dict | None:
        """
        Check if the user is logged in.
        """
        session_cookie = self.cookie_manager.get("user_data")
        if session_cookie:
            return {'user': 'joe', 'level': 1}
        # ToDo: Check parse jwt and check if its valid and then return the user dict

    def run(self) -> None:
        """
        Application entry point.
        """
        login = self._check_cookie_login()
        if login:
            self.set_access(1, login['user'], cache_access=True)
            self.do_redirect()

        st.markdown("<h1 style='text-align: center;'>Secure Hydralit Login</h1>", unsafe_allow_html=True)

        c1, c2, c3, = st.columns([2, 2, 2])

        form_data = self._create_login_form(c2)

        pretty_btn = """
        <style>
        div[class="row-widget stButton"] > button {
            width: 100%;
        }
        </style>
        <br><br>
        """
        c2.markdown(pretty_btn, unsafe_allow_html=True)

        if form_data['submitted']:
            self._do_login(form_data, c2)

    @staticmethod
    def _create_login_form(parent_container) -> Dict:

        login_form = parent_container.form(key="login_form")

        form_state = {}
        form_state['username'] = login_form.text_input('Username')
        form_state['password'] = login_form.text_input('Password', type="password")
        form_state['submitted'] = login_form.form_submit_button('Login')

        parent_container.write("sample login -> joe & joe")

        return form_state

    def _do_login(self, form_data, msg_container) -> None:

        # access_level=0 Access denied!
        access_level = self._check_login(form_data)

        if access_level > 0:
            msg_container.success(f"โœ”๏ธ Login success")
            with st.spinner("๐Ÿค“ now redirecting to application...."):
                time.sleep(1)

                self.set_access(1, form_data['username'], cache_access=True)
                self.cookie_manager.set("user_data", 'True')
                # Do the kick to the home page
                self.do_redirect()
        else:
            self.session_state.allow_access = 0
            self.session_state.current_user = None

            msg_container.error(f"โŒ Login unsuccessful, ๐Ÿ˜• please check your username and password and try again.")

    def _check_login(self, login_data) -> int:

        if login_data['username'] == 'joe' and login_data['password'] == 'joe':
            return 1
        else:
            return 0

The above basically checks if there is a cookie with name user_data and logs in automatically if its set.
When the cookie is not found it loads the modified example from example code.

When the username and password matches. It should set a cookie with name user_data but this fails here.
But doing the same using login_callback in app.py works

@app.logout_callback
def mylogout_cb():
    cookie_manager.delete('user_data')
    print('I was called from Hydralit at logout!')

@app.login_callback
def mylogin_cb():
    print('I was called from Hydralit at login!')
    cookie_manager.set('user_data', "Joe")

Now whenever I reload the page I can skip the login page. But hitting the logout button sends invokes the mylogout_cb function. But cookie_manager.delete('user_data') has no effect and doesn't delete the cookie.

But putting the same cookie_manager.delete('user_data') inside the mylogin_cb callback actually deletes the cookie on next login / on page reload.

Am i missing something here ?. What would be the best way for me to achieve this. I tried extra_streamlit_components library and it has the same behaviour

thank you/small bug

howdy, this is incredible work. I want to be you.

The loading_app in hydra_app points to a resources/failure.png file that comes with hydra-examples, but not with the module itself. It eclipses other error messages with "cant find failure.png". I think that line just needs to be wiped.

st_ver variable in hydralit/sessionstate.py

From last commit: st_ver = 890 with streamlit version 0.8.9, which raises error

from streamlit.script_run_context import get_script_run_ctx
ModuleNotFoundError: No module named 'streamlit.script_run_context'

because streamlit version < 0.8.x go through else: statement :

if st_ver < 140:
    import streamlit.report_thread as ReportThread
    from streamlit.server.server import Server
else:
    from streamlit.script_run_context import get_script_run_ctx
    from streamlit.server.server import Server

Issue facing while trying to add Signup App

Hello @TangleSpace

We followed the steps similar to login app and home app both are working fine and we also wanted to add extra feature like signup app.But we faced issue for redirecting the signup and we're struck at that place.

Signup app is working fine individually, like inserting details of user into database while calling the file individually. But when we're trying to call through a button click but instead of going to signup page we're redirecting to blank page.

We added

In hydra_app.py file we mentioned is_signup=False

def add_app(self, title, app, icon=None, is_login=False, is_signup=False is_home=False, logout_label=None):

For the Hydralit Framework there's no specific documentation. If there's any possibility to share the documentation please keep it.

No module 'streamlit.script_run_context'

Hi there. I am running Streamlit 1.8.1 (the latest, I think). When I try and run my Hydralit app, I get the following:

ModuleNotFoundError: No module named 'streamlit.script_run_context'

This seems to be part of the sessionstate.py file.

Can something be done to fix this on my side?

Error when running app.run()

I've tried running my website and I have encountered the following error: ModuleNotFoundError: No module named 'streamlit.scriptrunner'

Here's my code if you wanna try and replicate it

import hydralit as hy

if __name__ == '__main__':
    app = hy.HydraApp(
        title="Trivia App",
        hide_streamlit_markers=True,
    )

    app.run()

Problem with session_id

Hi!, i'm trying to make a multi page with hydralit and i keep gettin this error:

AttributeError: 'NoneType' object has no attribute 'session_id'

I found a answer to this problem in the streamlit webb, wich was:

`
def _get_state(hash_funcs=None):
try:
session = _get_session()
except (AttributeError, NameError):
session = sys

    if not hasattr(session, "_custom_session_state"):
        session._custom_session_state = _SessionState(session, hash_funcs)

    return session._custom_session_state

`

But when i dont' really know how to do it, when i call this function in my code gives me another error:

NameError: name '_get_session' is not defined

Change nav bar color

First, thanks for the awesome job to create Hydralit, there is great synergy with Streamlit.

My question is quite not related to "technical aspects", but more to "design". How do I change the color of the navbar? Currently, it is red. I'd like to set my own, perhaps setting with color hex code.
Thanks a million!

Unable to redirect to Signup page

Hello @TangleSpace

We used secure hydra login for this entire process.

We added a new button Signup in Login Page.

We wanted to redirect to Signup Page from login page.

We are unable to redirect to signup page after clicking the signup button.

We are facing an issue.
Screenshot (11)
Screenshot (12)

Redirect from Signup to loginapp

Hello @TangleSpace

I've made changes to your code. I just included the database connectivity to save the username and password.

I'm trying to redirect from Signup App to Login App.

I've read in hydralit(app_template) that if nothing is mentioned in self.do_redirect() present in def _do_signup(self, form_data, msg_container) -> None:
then it will be redirected to homepage by default.

But I've mentioned (apps.login_app) in self.do_redirect(apps.login_app) which is in init.py file.
I've also mentioned login_app in self.do_redirect(login_app) but it is still redirecting to home page.

hydralit(app_template)

def do_redirect(self,redirect_target_app=None):
"""
Used to redirect to another app within the parent application. If the redirect_target is a valid url, a new window will open and the browser will set focus on the new window while leaving this app in it's current state.

    Parameters
    ------------
    redirect_target_app: str, None
        The name of the target app or a valid url, this must be the registered name when the app was added to the parent. If no target is provided, it will redirect to the HydraApp home app. If the redirect_target is a valid url, a new window will open and the browser will set focus on the new window while leaving this app in it's current state.

Signup app code:

def _create_signup_form(self, parent_container) -> Dict:

    login_form = parent_container.form(key="login_form")

    form_state = {}
    form_state['username'] = login_form.text_input('Username')
    form_state['fullname'] = login_form.text_input('Fullname')
    form_state['password'] = login_form.text_input('Password',type="password")
    form_state['password2'] = login_form.text_input('Confirm Password',type="password")
    form_state['access_level'] = login_form.selectbox('Example Access Level',(1,2))
    form_state['submitted'] = login_form.form_submit_button('Sign Up')

    if parent_container.button('Login',key='loginbtn'):
        # set access level to a negative number to allow a kick to the unsecure_app set in the parent
        self.set_access(0, None)

        #Do the kick to the signup app
        self.do_redirect('LoginApp')

    return form_state

def _do_signup(self, form_data, msg_container) -> None:
    if form_data['submitted'] and (form_data['password'] != form_data['password2']):
        st.error('Passwords do not match, please try again.')
    else:
        with st.spinner("๐Ÿค“ now redirecting to login...."):
            self._save_signup(form_data)
            time.sleep(2)

            #access control uses an int value to allow for levels of permission that can be set for each user, this can then be checked within each app seperately.
            self.set_access(0, None)
            self.set_access(form_data['access_level'], form_data['username'])
            #Do the kick back to the login screen
            self.do_redirect("apps.login_app")

Can you please guide me.

Set menu_items from page config

Hi there!

Is there a way to change the menu_items option (usually set in st.set_page_config) using Hydralit/the class Hydrapp? How would I specify these using Hydralit?

Switch apps when looping for realtime update

The site either does a long lag or does not switch at all when a new app is selected on the navbar.

The app contains a while true loop

while True:
   st.write()
thread.Sleep(10)

Login Page Modifications

We made modifications for the existing secure login.

we struck at a point where we are unable to redirect to next page after succesful login.

Scenario:

After succesful login we want to redirect to home page but we're at login page itself with this error

AttributeError: 'LoginApp' object has no attribute 'session_state'

Traceback:
File "C:\Users\anaconda3\lib\site-packages\streamlit\script_runner.py", line 350, in _run_script
exec(code, module.dict)
File "C:\Users\Downloads\hydralit-example-main - Copy\hydralit-example-main\apps\login_app.py", line 161, in
c.run()
File "C:\Users\Downloads\hydralit-example-main - Copy\hydralit-example-main\apps\login_app.py", line 98, in run
self._do_login(form_data, c2)
File "C:\Users\Downloads\hydralit-example-main - Copy\hydralit-example-main\apps\login_app.py", line 127, in _do_login
self.set_access(form_data['access_level'], form_data['username'])
File "C:\Users\anaconda3\lib\site-packages\hydralit\app_template.py", line 54, in set_access
self.session_state.allow_access = allow_access

Erros won't be displayed on app page

On version hydralit==1.0.10, when there is an error in the code, hydralit doens't have the default behaviour of streamlit of showing the error message on the page, instead it tries to show a failure image.

image

Is there a way to have the usual behaviour and simply show the error message?

integrating streamlit authlib & hydralit

Hi,

I'm trying to figure out the best strategy for adding the necessary functions to the hydralit authentication model -- basically it looks to me as if I need a SQL db to store user info & CRUD functions to check/modify them. WHat I am wondering is whether I can bolt arvindra's authlib into your framework. Can you see any major obstacles or advantages either way?

https://pythonrepo.com/repo/asehmi-auth-simple-for-streamlit-python-implementing-authentications-schemes

The alternative is writing the necessary functions for myself from scratch, which I can do, but what makes me nervous is not knowing much about authentication, don't want to overlook obvious gotchas.

Child app loading twice when using internal redirect from another app

When you launch a page from the text button links on the Home page, its content appears twice, e.g.

function result (SolarMach page)
function result (SolarMach page)

This only occurs from the text button links in the center of the page, not from the links in the complex nav.

missing container message during login

Hi,

I'm making progress on the authentication front but run into an issue I don't understand. I modified the "save signup data" function as below. the authlib _create_user function requires authentication so i am making the save signup data function authenticate using hydralit's LoginApp.do_login before it tries to _create_user. This is almost working (I think) but _do_login wants to know the current msg_container, which I don't know.


    def _save_signup(self, signup_data):

        # show the data we captured
        what_we_got = f"""
        captured signup details: \n
        username: {signup_data['username']} \n
        password: {signup_data['password']} \n
        access level: {signup_data['access_level']} \n
        """
        st.write(what_we_got)

        try:
            **LoginApp._do_login("test", "test2")
            _create_user(username=signup_data['username'], password=signup_data['password'], is_su=False, mode='create')**
            st.write(signup_data)
            st.write('User created successfully')
        except Exception as e:
            st.write(e)

on running signup.py:

captured signup details:
username: meme
password: meme2828
access level: 1

TypeError: _do_login() missing 1 required positional argument: 'msg_container'
Traceback:
File "nimbleunity/apps/signup.py", line 104, in _save_signup
    LoginApp._do_login("test", "test2")

Doesn't work with streamlit cloud

App doesn't run on streamlit cloud.
This is VERY frustrating given how much I enjoy this library, and sadly I can't even make it run on their servers even tho this is fully streamlit based.

Please fix asap or share a solution, needed for a job interview

Import Syntax Issues With Streamlit 1.12.2

Trying to build a website using Hydralit, and encountered ModuleNotFound errors immediately upon importing the library.

It seems like at some point Streamlit changed around their code schema; changing two lines in sessionstate.py seemed to do the trick:

# from
from streamlit.scriptrunner.script_run_context import get_script_run_ctx

# to
from streamlit.runtime.scriptrunner.script_run_context import get_script_run_ctx

and

# from
from streamlit.server.server import Server

# to
from streamlit.web.server import Server

I'm pretty new to Streamlit/Hydralit, but hopefully these changes won't break anything else? Seems to be working just fine from the testing I've been doing.

page state?

Does this support page state, so if you go to another page and comeback control values in session.state
are not reset.?
Couldn't see how to support this.

weird-looking visual effect under nav bars

There's a weird-looking transition effect occurring underneath the nav bar. I have the following values set:

[theme]
base="light"
primaryColor="#B21030"
backgroundColor="#FFFFFF"
secondaryBackgroundColor="#ceb829"

Screen Shot 2021-09-26 at 12 50 10 AM

Is this anything close to intentional?

AttributeError in add_app Method when Using Hydralit

AttributeError in add_app Method when Using Hydralit

Description

I encountered an issue while using the add_app method in Hydralit, resulting in an AttributeError. This problem occurs specifically when trying to add applications to the HydraApp instance. Below are the details of the error and the environment in which it occurs.

Steps to Reproduce

  1. Initialize a HydraApp instance.
  2. Attempt to add an app using app.add_app("App Title", app_function).
  3. Encounter the AttributeError on running the application.

Expected Behavior

The application should be added to the HydraApp without any errors, allowing for seamless navigation between different apps.

Actual Behavior

An AttributeError is thrown, stating:

AttributeError: 'function' object has no attribute 'assign_session'

Environment

  • Hydralit Version: 1.0.14
  • Streamlit Version: [1.34.0]
  • Python Version: [3.9.18]
  • Operating System: [Windows11 22H2 ]

Additional Context

Please include any additional information that might be helpful for diagnosing the issue, such as code snippets or screenshots.

Thank you for looking into this issue!

Best regards,
[Kyo]

The uploaded video file co-exists among different apps

The first step in all apps is to upload a video file, like

f = st.file_uploader("upload video")
st.video(f)

If I upload the video in app1, and then navigate to app2, the video also shows.
Is there any solutio to clear the components in app2?
Thanks.

hydralit 1.0.12 and streamlit 1.9.0

Hi !

When I try to implement hydralit 1.0.12 in my App (I use streamlit 1.9.0) the following error occurs:

from streamlit.script_run_context import get_script_run_ctx
ModuleNotFoundError: No module named 'streamlit.script_run_context'

It would be great if you could fix this. Thank you for sharing hydralit with us! :)

Does hydralit 1.0.11 require disk C access?

First of all would like to thank you for hydralit, it makes building secure and multipage web app easy.

I have a question regarding the latest version of hydralit, when I run

easy_install "hydralit==1.0.11"

I receive this error

error: SandboxViolation: mkdir('C:\Users\XXXX\.matplotlib', 511) {}

The package setup script has attempted to modify files on your system
that are not within the EasyInstall build area, and has been aborted.

This package cannot be safely installed by EasyInstall, and may not
support alternate installation locations even if you run its setup
script by hand. Please inform the package's author and the EasyInstall
maintainers to find out if a fix or workaround is available.

But when I run

easy_install "hydralit==1.0.10"

The installation runs successfully. Does the newest version require C disk access?

PS: I'm using easy_install instead of pip because I have some issues with my internet connection proxy

after file upload from subpage, hydralit is returning user to home page

import streamlit as st
from hydralit import HydraHeadApp
... 

class CreateMetadataApp(HydraHeadApp):

    def __init__(self, title = 'Nimble Books: Unity', **kwargs):
        self.__dict__.update(kwargs)
        self.title = title

    def run(self):
      ...
        st.title("Prepare a Completed Manuscript for Publication")
     ...
        uploaded_file = st.file_uploader(   
            "Upload your completed manuscript", type=['pdf', 'docx', 'doc', 'txt'], accept_multiple_files=False, help = "Upload your completed manuscript that is ready for publication.", args=None, kwargs=None)

        if uploaded_file is not None:
            # do stuff

** instead of doing stuff, returns to Hydra homeapp page **
Why is this happening?

Latest streamlit version not supported

Hi, I'm having issue using the package.

Traceback (most recent call last):
  File "/home/irfan/PycharmProjects/TES-Search/multiapp.py", line 1, in <module>
    import hydralit as hy
  File "/home/irfan/environments/The-Entities-Swissknife/lib/python3.7/site-packages/hydralit/__init__.py", line 5, in <module>
    from hydralit.hydra_app import HydraApp
  File "/home/irfan/environments/The-Entities-Swissknife/lib/python3.7/site-packages/hydralit/hydra_app.py", line 4, in <module>
    from hydralit.sessionstate import SessionState
  File "/home/irfan/environments/The-Entities-Swissknife/lib/python3.7/site-packages/hydralit/sessionstate.py", line 8, in <module>
    from streamlit.script_run_context import get_script_run_ctx
ModuleNotFoundError: No module named 'streamlit.script_run_context'

How to change the default big loader?

I'm making a streamlit app based on the hydralit-example: https://github.com/TangleSpace/hydralit-example

My app loads some data at first from database. While this is happening a rather large loading screen is present.
image

How can I tame this loader and select a more compact one?

The structure of the code I use for the app-page:
import hydralit as hy
import pandas as pd
import streamlit as st

#create a wrapper class
class generate_app_page(hy.HydraHeadApp):
def run(self):
col1, col2 = hy.columns([2,4])
msr = col1.selectbox('some nice label', get_ids_from_db())

allow more than 1 insecure app

Hello, is there some extremely important reason why there has to be a hard limit of 1 insecure app? In my use case I probably want to have several insecure apps that provide frictionless access to documentation and public data v. several secure ones with premium data.

Nav Bar oriented vertically rather than horizontally

I am new to this library but have been having issues orienting the navigation bar horizontally in my Streamlit app. It seems to be defaulting to a vertical orientation despite me having copy and pasted the example code from the github repo. Find my code below and a screenshot of the app attached.
Screenshot 2023-11-20 155028

import streamlit as st
from hydralit.app_template import HydraHeadApp
import hydralit_components as hc
import apps

# Define RGB colors
medium_blue = (91, 155, 213)
bright_blue = (44, 170, 226)
dark_blue = (35, 50, 103)
white = (255, 255, 255)

# Main Navigation App
class MainApp(HydraHeadApp):
    def run(self):

        with st.sidebar:
            st.markdown('**Brought to you by the [Data Collaborative for Justice](https://datacollaborativeforjustice.org/) at John Jay College of Criminal Justice**', unsafe_allow_html=True)
            st.image("images\\DCJ_logo_Horizonal_JJ.png")

        #navigation bar
        menu_data = [
            {'label': "Projections"},
            {'label': "Monthly Trends"},
            {'label': "Disparities"},
            {'label': "Contact Us"}
        ]

        over_theme = {'txc_inactive': '#FFFFFF', 'menu_background':f'rgb{medium_blue}','txc_active': f'rgb{dark_blue}'}

        menu_id = hc.nav_bar(
            menu_definition=menu_data,
            override_theme=over_theme,
            home_name='Home',
            hide_streamlit_markers=False, #will show the st hamburger as well as the navbar now!
            sticky_nav=True, #at the top or not
            sticky_mode='pinned', #jumpy or not-jumpy, but sticky or pinned
        )    
        
        if menu_id == "Home":
            home_page = apps.HomePage()
            home_page.run()
        elif menu_id == "Projections":
            projections = apps.Projections()
            projections.run()
        elif menu_id == "Monthly Trends":
            monthly_trends = apps.MonthlyTrends()
            monthly_trends.run()
        elif menu_id == "Disparities":
            disparities = apps.Disparities()
            disparities.run()


# Run the app
if __name__ == "__main__":
    main_app = MainApp()
    main_app.run()

Keyed widget values are lost when switching the pages

I have a two page application where in one of them I have a few widgets like text box which is connected to a session state variable via the key. It works fine until I am in this page but if I open the other page and comeback again then the widget values and their session state values are lost. I tried this solution https://gist.github.com/okld/8ca97ba892a7c20298fd099b196a8b4d
but it fails and shows the error:
Error details: Values for st.button, st.download_button, st.file_uploader, and st.form cannot be set using st.session_state.
Any suggestion?

The Navbar changes when st.title added

Hi, thank you for your awesome work.

I'm trying to build my web app using Hydralit, but facing a little problem. I want to add title above navbar like code below.
But the navbar changes when I add st.title as you can see in the images. Is there any way I can add title and keep the original navbar?

from hydralit import HydraApp
import streamlit as st
from Front.first_tab import first_tab_generator
from Front.second_tab import second_tab_generator

if __name__ == '__main__':
    st.title('Bot Test')
    app = HydraApp(title='Hydra_test', favicon="๐Ÿ“š")       

    app.add_app("First Tab", app=first_tab_generator())   
    app.add_app("Second Tab", app=second_tab_generator())   
    app.run()

Image with original Navbar
image

Navbar changes when I add st.title
image

Thanks in advance.

self.do_redirect does not change the menu option in the navbar

Hello @TangleSpace! I love this package!

I hope I am not doing something wrong, but when I put the code self.do_redirect("Title of app to run") in my code on a button, the relevant app does run, but the navbar does not change to reflect this. It stays on the navbar option of the original app where the button is housed.

Did I miss something, or do something incorrectly?

Update for using `st.session_state`

As of Streamlit 1.12, the older API used to hack in a SessionState has been entirely deprecated (with an ugly hack to retrieve the Server from the GC) in favour of the built-in st.session_state. This comes from the advice of this gist here: https://gist.github.com/tvst/036da038ab3e999a64497f42de966a92

I'd be happy to contribute a pull request (I think it should be minor changes), though my only concern is that hydralit_components may require the old SessionState. Could any of the maintainers of either repository comment on this?

Loaders and spacing

Hi there! This package is great.

Two quick questions: I've integrated an existing app into Hydralit, but the top menu is appearing about an inch below the top of the screen. Is there a way to move it to the top?

And, when I load a page/app I get all three loaders with the large text that is is "Loading now". Is there a way to customize which loader shows and remove/format the text?

How to disable the (huge) "Now Loading YOUR.APP"

We are exploring Hydralit.

One thing we do not quite appreciate is the huge "Now Loading YOUR.APP" notification when a page is starting up. We have not found in the docs the proper way to disable these.

Any suggestion?

type objct 'Server' has not attribute 'get_current'

Error Trace:

File "/home/ali/miniconda3/envs/streamlit-app/lib/python3.10/site-packages/hydralit/hydra_app.py", line 155, in init
self.session_state = SessionState.get(previous_app=None, selected_app=None,other_nav_app=None, preserve_state=preserve_state, allow_access=self._no_access_level,logged_in=False,access_hash=None)
File "/home/ali/miniconda3/envs/streamlit-app/lib/python3.10/site-packages/hydralit/sessionstate.py", line 76, in get
session_info = Server.get_current()._get_session_info(session_id)

Login and Logout through Hydralit!

Hi there! I have recently discovered hydralit and I love the library so far. I am trying to built a login page that will redirect me to the page with multiple applications. In the hydralit example, I had noticed that there is a feature for Logout available which will redirect the user back to the login page.

My code for the Login page is as follows:

class LoginApp(HydraHeadApp):
def run(self):
c1, c2, c3 = st.columns(3)
c1.write(" ")
with c2:
st.title("Login")
if st.button('Guest Login', key='guestbtn'):
st.success(f"โœ”๏ธ Login success")
with st.spinner("๐Ÿค“ now redirecting to application...."):
time.sleep(1)
self.set_access(1, 'guest')
self.do_redirect()
c3.write(" ")

The page gets redirected to my home page but there is an additional tab next to the home page with the title "Login" and there's an error:

๐Ÿ˜ญ Error triggered from app: Logout
Details: โ€˜Logoutโ€™

Am I missing something out here? Do I have to include additional code anywhere?

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.