├── .gitattributes
├── 9781484281109.JPG
├── Chapter_1
├── main.py
└── unit_test.py
├── Chapter_10
└── main.py
├── Chapter_2
├── conditional_flow_1.py
├── conditional_flow_2.py
├── dataframe_demo.py
├── input_form.py
├── interactive_line_chart.py
├── interactive_map.py
├── markdown_code.py
├── markdown_header_sizes.py
├── markdown_hyperlink.py
├── markdown_image.py
├── markdown_lists.py
├── markdown_quote.py
├── markdown_table.py
├── markdown_text_styling.py
├── mutate_dataframe_arrange.py
├── mutate_dataframe_filter.py
├── mutate_dataframe_groupby.py
├── mutate_dataframe_merge.py
├── mutate_dataframe_mutate.py
├── mutate_dataframe_select.py
├── static_bar_chart.py
├── static_line_chart.py
├── try_and_except_1.py
├── try_and_except_2.py
├── webapp.bat
└── without_try_and_except.py
├── Chapter_3
├── API-__init__.py
├── API.py
├── AddPost.py
├── AddPostView.py
├── FeedView.py
├── GetFeed.py
├── Post.py
├── Views-__init__.py
├── config.toml
├── footer.py
├── main.py
├── main_page.py
├── main_page_subpage.py
├── page_1.py
├── page_2.py
├── page_config.py
├── page_organization.py
├── placeholder.py
├── progress_bar.py
├── remove_footer_menu.py
├── subpage_1_1.py
└── subpage_1_2.py
├── Chapter_5
├── df_demo.py
├── main.py
└── secrets.toml
├── Chapter_6
├── Base.py
├── Employees.py
├── PayGrades.py
├── flask_sample.py
├── main.py
├── sample_json.json
├── streamlit_api.py
└── streamlit_main.py
├── Chapter_7
├── cookie_management.py
├── session_id_demo.py
└── session_state.py
├── Chapter_8
├── .gitignore
├── API.py
├── AddEmployee.py
├── Admins.py
├── DisplayEmployees.py
├── HashingService.py
├── JWTService.py
├── Login.py
├── Middleware.py
├── flask_main.py
├── secrets.example.yaml
└── streamlit_main.py
├── Contributing.md
├── LICENSE.txt
└── README.md
/.gitattributes:
--------------------------------------------------------------------------------
1 | # Auto detect text files and perform LF normalization
2 | * text=auto
3 |
--------------------------------------------------------------------------------
/9781484281109.JPG:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/Apress/Web-Application-Development-with-Streamlit/d5c2b92e9d51fc0fa4f49011334224fccaf906ee/9781484281109.JPG
--------------------------------------------------------------------------------
/Chapter_1/main.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 |
4 | def calculate_sum(n1, n2):
5 | return n1 + n2
6 |
7 |
8 | st.title("Add numbers")
9 |
10 | n1 = st.number_input("First Number")
11 | n2 = st.number_input("Second Number")
12 |
13 | if st.button("Calculate"):
14 | st.write("Summation is: " + str(calculate_sum(n1, n2)))
15 |
--------------------------------------------------------------------------------
/Chapter_1/unit_test.py:
--------------------------------------------------------------------------------
1 | from main import calculate_sum
2 | from selenium import webdriver
3 | from selenium.webdriver.chrome.options import Options
4 | import time
5 |
6 |
7 | def test_user_interface():
8 | driver_path = r"----------\chromedriver.exe" # Path to chromedriver. Can end with .sh if on (Li/U)nix environments
9 | options = Options()
10 | options.add_argument("--headless") # To not open a real chrome window
11 | with webdriver.Chrome(driver_path, chrome_options=options) as driver:
12 | url = "http://127.0.0.1:8501"
13 | driver.get(url)
14 | time.sleep(5)
15 | html = driver.page_source
16 |
17 | assert "Add numbers" in html
18 | assert "First Number" in html
19 | assert "Second Number" in html
20 |
21 |
22 | def test_logic():
23 | assert calculate_sum(1, 1) == 2
24 | assert calculate_sum(1, -1) == 0
25 | assert calculate_sum(1, 9) == 10
26 |
27 |
28 | if __name__ == "__main__":
29 | test_logic()
30 | test_user_interface()
31 |
--------------------------------------------------------------------------------
/Chapter_10/main.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.title("Welcome, WWW")
4 |
5 | url = "https://www.whatismyip-address.com"
6 |
7 | script = f"""
8 |
9 | """
10 |
11 | st.write(script, unsafe_allow_html=True)
12 | st.write(f"Check out your [public IP]({url})")
13 |
--------------------------------------------------------------------------------
/Chapter_2/conditional_flow_1.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | def display_name():
4 | st.info('**Name:** %s' % (name))
5 |
6 | name = st.text_input('Please enter your name')
7 |
8 | if not name:
9 | st.error('No name entered')
10 |
11 | if name:
12 | display_name()
13 |
--------------------------------------------------------------------------------
/Chapter_2/conditional_flow_2.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | def display_name():
4 | st.info('**Name:** %s' % (name))
5 |
6 | name = st.text_input('Please enter your name')
7 |
8 | if not name:
9 | st.error('No name entered')
10 | st.stop()
11 |
12 | display_name()
13 |
--------------------------------------------------------------------------------
/Chapter_2/dataframe_demo.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import plotly.express as px
4 |
5 | df = px.data.stocks()
6 | st.title('DataFrame Demo')
7 | program = st.sidebar.selectbox('Select program',['Dataframe Demo'])
8 | code = st.sidebar.checkbox('Display code')
9 | stocks = st.multiselect('Select stocks',df.columns[1:],[df.columns[1]])
10 | st.subheader('Stock value')
11 |
12 | # Mutating the dataframe to keep selected columns only
13 | st.write(df[['date'] + stocks].set_index('date'))
14 |
15 | # Creating a Plotly timeseries line chart
16 | fig = px.line(df, x='date', y=stocks,
17 | hover_data={"date": "|%Y %b %d"}
18 | )
19 |
20 | st.write(fig)
21 |
22 | if code is True:
23 | st.code(
24 | """
25 | import streamlit as st
26 | import pandas as pd
27 | import plotly.express as px
28 |
29 | df = px.data.stocks()
30 | st.title('DataFrame demo')
31 | program = st.sidebar.selectbox('Select program',['Dataframe Demo'])
32 | code = st.sidebar.checkbox('Display code')
33 | stocks = st.multiselect('Select stocks',df.columns[1:],[df.columns[1]])
34 | st.subheader('Stock value')
35 | st.write(df[['date'] + stocks].set_index('date'))
36 |
37 | fig = px.line(df, x='date', y=stocks,
38 | hover_data={"date": "|%Y %b %d"}
39 | )
40 |
41 | st.write(fig)
42 | """
43 | )
44 |
--------------------------------------------------------------------------------
/Chapter_2/input_form.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | with st.form('feedback_form'):
4 | st.header('Feedback form')
5 |
6 | # Creating columns to organize the form
7 | col1, col2 = st.columns(2)
8 | with col1:
9 | name = st.text_input('Please enter your name')
10 | rating = st.slider('Please rate this app',0,10,5)
11 | with col2:
12 | dob = st.date_input('Please enter your date of birth')
13 | recommend = st.radio('Would you recommend this app to others?',('Yes','No'))
14 |
15 | submit_button = st.form_submit_button('Submit')
16 |
17 | if submit_button is True:
18 | st.write('**Name:**', name, '**Date of birth:**', dob, '**Rating:**', rating, '**Would recommend?:**', recommend)
19 |
--------------------------------------------------------------------------------
/Chapter_2/interactive_line_chart.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import plotly.graph_objects as go
4 |
5 | df = pd.DataFrame(data={'Exam':['Exam 1','Exam 2','Exam 3'],
6 | 'Jessica':[77,76,87],'John':[56,97,95],'Alex':[87,82,93]}
7 | )
8 | fig = go.Figure(data=[
9 | go.Line(name='Jessica', x=df['Exam'], y=df['Jessica']),
10 | go.Line(name='John', x=df['Exam'], y=df['John']),
11 | go.Line(name='Alex', x=df['Exam'], y=df['Alex'])
12 | ])
13 |
14 | fig.update_layout(
15 | xaxis_title='Exam',
16 | yaxis_title='Score',
17 | legend_title='Name',
18 | )
19 |
20 | st.plotly_chart(fig)
21 |
--------------------------------------------------------------------------------
/Chapter_2/interactive_map.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import plotly.graph_objects as go
4 |
5 | df = pd.DataFrame(data={'university':['Harvard University','Yale University',
6 | 'Princeton University','Columbia University','Brown University',
7 | 'Dartmouth University','University of Pennsylvania','Cornell University'],
8 | 'latitude':[42.3770,41.3163,40.3573,40.8075,41.8268,43.7044,39.9522,42.4534],
9 | 'longitude':[-71.1167,-72.9223,-74.6672,-73.9626,-71.4025,-72.2887,
10 | -75.1932,-76.4735]}
11 | )
12 |
13 | fig = go.Figure(data=go.Scattergeo(
14 | lon = df['longitude'],
15 | lat = df['latitude'],
16 | text = df['university'],
17 | ))
18 |
19 | fig.update_layout(
20 | geo_scope='usa',
21 | )
22 |
23 | st.plotly_chart(fig)
24 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_code.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown(
4 | '''
5 | ```
6 | def hello_world():
7 | print('Hello world')
8 | ```
9 | '''
10 | )
11 | st.markdown(
12 | '''
13 | ```python
14 | def hello_world():
15 | print('Hello world')
16 | ```
17 | '''
18 | )
19 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_header_sizes.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown(
4 | '''
5 | # Hello world
6 | ## Hello world
7 | ### Hello world
8 | #### Hello world
9 | ##### Hello world
10 | ###### Hello world
11 | '''
12 | )
13 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_hyperlink.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown('Check out [Streamlit](https://streamlit.io/)')
4 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_image.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown('')
4 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_lists.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown(
4 | '''
5 | - Hello world
6 | - Hello world
7 | - Hello world
8 | '''
9 | )
10 | st.markdown(
11 | '''
12 | 1. Hello world
13 | 2. Hello world
14 | 3. Hello world
15 | '''
16 | )
17 | st.markdown(
18 | '''
19 | - [x] Hello world
20 | - [ ] Hello world
21 | '''
22 | )
23 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_quote.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown('> Hello world')
4 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_table.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown(
4 | '''
5 | Name | Score 1 | Score 2
6 | ------------ | ------------- | -------------
7 | Jessica | 77 | 76
8 | John | 56 | 97
9 | Alex | 87 | 82
10 | '''
11 | )
12 |
--------------------------------------------------------------------------------
/Chapter_2/markdown_text_styling.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | st.markdown('**Hello world**')
4 | st.markdown('_Hello world_')
5 | st.markdown('~~Hello world~~')
6 |
--------------------------------------------------------------------------------
/Chapter_2/mutate_dataframe_arrange.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import numpy as np
4 |
5 | df = pd.DataFrame(
6 | np.random.randn(4, 3),
7 | columns=('Column 1','Column 2','Column 3')
8 | )
9 | st.subheader('Original dataframe')
10 | st.write(df)
11 |
12 | st.subheader('Mutated dataframe')
13 | st.write(df.sort_values(by='Column 1',ascending=True))
14 |
--------------------------------------------------------------------------------
/Chapter_2/mutate_dataframe_filter.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import numpy as np
4 |
5 | df = pd.DataFrame(
6 | np.random.randn(4, 3),
7 | columns=('Column 1','Column 2','Column 3')
8 | )
9 | st.subheader('Original dataframe')
10 | st.write(df)
11 |
12 | st.subheader('Mutated dataframe')
13 | st.write(df[df['Column 1'] > -1])
14 |
--------------------------------------------------------------------------------
/Chapter_2/mutate_dataframe_groupby.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import numpy as np
4 |
5 | df = pd.DataFrame(
6 | np.random.randn(12, 3),
7 | columns=('Score 1','Score 2','Score 3')
8 | )
9 |
10 | df['Name'] = pd.DataFrame(['John','Alex','Jessica','John','Alex','John',
11 | 'Jessica','John','Alex','Alex','Jessica','Jessica'])
12 |
13 | df['Category'] = pd.DataFrame(['B','A','D','C','C','A',
14 | 'B','C','B','A','A','D'])
15 |
16 | st.subheader('Original dataframe')
17 | st.write(df)
18 |
19 | st.subheader('Mutated dataframe')
20 | st.write(df.groupby(['Name','Category']).first())
21 |
--------------------------------------------------------------------------------
/Chapter_2/mutate_dataframe_merge.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 |
4 | df1 = pd.DataFrame(data={'Name':['Jessica','John','Alex'],
5 | 'Score 1':[77,56,87]}
6 | )
7 |
8 | df2 = pd.DataFrame(data={'Name':['Jessica','John','Alex'],
9 | 'Score 2':[76,97,82]}
10 | )
11 |
12 | st.subheader('Original dataframes')
13 | st.write(df1)
14 | st.write(df2)
15 |
16 | st.subheader('Mutated dataframe')
17 | st.write(df1.merge(df2,how='inner',on='Name'))
18 |
--------------------------------------------------------------------------------
/Chapter_2/mutate_dataframe_mutate.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import numpy as np
4 |
5 | df = pd.DataFrame(
6 | np.random.randn(4, 3),
7 | columns=('Column 1','Column 2','Column 3')
8 | )
9 | st.subheader('Original dataframe')
10 | st.write(df)
11 |
12 | st.subheader('Mutated dataframe')
13 | st.write(df.assign(Column_4 = lambda x: df['Column 1']*2))
14 |
--------------------------------------------------------------------------------
/Chapter_2/mutate_dataframe_select.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import numpy as np
4 |
5 | df = pd.DataFrame(
6 | np.random.randn(4, 3),
7 | columns=('Column 1','Column 2','Column 3')
8 | )
9 | st.subheader('Original dataframe')
10 | st.write(df)
11 |
12 | st.subheader('Mutated dataframe')
13 | st.write(df[['Column 1', 'Column 2']])
14 |
--------------------------------------------------------------------------------
/Chapter_2/static_bar_chart.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import matplotlib.pyplot as plt
4 |
5 | df = pd.DataFrame(data={'Name':['Jessica','John','Alex'],
6 | 'Score 1':[77,56,87],'Score 2':[76,97,82]}
7 | )
8 | df.set_index('Name').plot(kind='bar',stacked=False,xlabel='Name',ylabel='Score')
9 | st.pyplot(plt)
10 |
11 |
--------------------------------------------------------------------------------
/Chapter_2/static_line_chart.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 | import matplotlib.pyplot as plt
4 |
5 | df = pd.DataFrame(data={'Exam':['Exam 1','Exam 2','Exam 3'],
6 | 'Jessica':[77,76,87],'John':[56,97,95],'Alex':[87,82,93]}
7 | )
8 |
9 | df.set_index('Exam').plot(kind='line',xlabel='Exam',ylabel='Score',subplots=True)
10 | st.pyplot(plt)
11 |
--------------------------------------------------------------------------------
/Chapter_2/try_and_except_1.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | col1, col2 = st.columns(2)
4 |
5 | with col1:
6 | number_1 = st.number_input('Please enter the first number',value=0,step=1)
7 | with col2:
8 | number_2 = st.number_input('Please enter the second number',value=0,step=1)
9 |
10 | try:
11 | st.info('**%s/%s=** %s' % (number_1,number_2,number_1/number_2))
12 | except ZeroDivisionError:
13 | st.error('Cannot divide by zero')
14 | except:
15 | pass
16 |
--------------------------------------------------------------------------------
/Chapter_2/try_and_except_2.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | col1, col2 = st.columns(2)
4 |
5 | with col1:
6 | number_1 = st.number_input('Please enter the first number',value=0,step=1)
7 | with col2:
8 | number_2 = st.number_input('Please enter the second number',value=0,step=1)
9 |
10 | try:
11 | st.info('**%s/%s=** %s' % (number_1,number_2,number_1/number_2))
12 | except Exception as e:
13 | st.error(f'Error: {e}')
14 |
--------------------------------------------------------------------------------
/Chapter_2/webapp.bat:
--------------------------------------------------------------------------------
1 | call activate base
2 | cd C:/Users/U342185/Desktop/res-owfdmwebapp/
3 | streamlit run main.py
4 | pause
--------------------------------------------------------------------------------
/Chapter_2/without_try_and_except.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | col1, col2 = st.columns(2)
4 |
5 | with col1:
6 | number_1 = st.number_input('Please enter the first number',value=0,step=1)
7 | with col2:
8 | number_2 = st.number_input('Please enter the second number',value=0,step=1)
9 |
10 | st.info('**%s/%s=** %s' % (number_1,number_2,number_1/number_2))
11 |
--------------------------------------------------------------------------------
/Chapter_3/API-__init__.py:
--------------------------------------------------------------------------------
1 | from .API import API as _API
2 |
3 | api_instance = _API()
4 |
--------------------------------------------------------------------------------
/Chapter_3/API.py:
--------------------------------------------------------------------------------
1 | from Models import Post
2 | import datetime
3 |
4 |
5 | class API:
6 | def __init__(self, config=None):
7 | self.config = config
8 |
9 | def add_post(self, post: Post):
10 | # POST HTTP request to backend to add the post
11 | # Returns true as in post has been added
12 | return True
13 |
14 | def get_posts(self, start_date: datetime.datetime, end_data: datetime.datetime):
15 | # GET HTTP request to backend to posts within a time period
16 | # Returns a list of Posts
17 | return [Post("Adam", "Python is a snake", datetime.datetime(year=2021, month=5, day=1)),
18 | Post("Sara", "Python is a programming language", datetime.datetime(year=2021, month=5, day=3))]
19 |
--------------------------------------------------------------------------------
/Chapter_3/AddPost.py:
--------------------------------------------------------------------------------
1 | from API import api_instance
2 | from Models import Post
3 |
4 |
5 | def add_post(post: Post):
6 | if post is None or len(post.creator_name) == 0 or len(post.content) == 0:
7 | return None
8 |
9 | did_add = api_instance.add_post(post)
10 |
11 | return did_add
12 |
--------------------------------------------------------------------------------
/Chapter_3/AddPostView.py:
--------------------------------------------------------------------------------
1 | import datetime
2 | import streamlit as st
3 | from Models import Post
4 | from typing import Callable
5 |
6 |
7 | class AddPostView:
8 | def __init__(self, add_post_func: Callable[[Post], bool]):
9 | user_name_text = st.text_input("Displayed name?")
10 | post_text = st.text_input("What's in your mind?")
11 | clicked = st.button("Post")
12 | if clicked:
13 | post = Post(creator_name=user_name_text, content=post_text, posting_date=datetime.datetime.now())
14 | did_add = add_post_func(post)
15 |
16 | if did_add:
17 | st.success("Post added!")
18 | else:
19 | st.error("Error adding post")
20 |
--------------------------------------------------------------------------------
/Chapter_3/FeedView.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from Models import Post
3 | from typing import Callable
4 |
5 |
6 | class FeedView:
7 | def __init__(self, get_feed_func: Callable[[], list]):
8 | posts = get_feed_func()
9 | for post in posts:
10 | _PostView(post)
11 |
12 |
13 | class _PostView:
14 | def __init__(self, post: Post):
15 | st.write(f"**{post.creator_name}**: {post.content} | _{post.posting_date}_")
16 |
--------------------------------------------------------------------------------
/Chapter_3/GetFeed.py:
--------------------------------------------------------------------------------
1 | from API import api_instance
2 | import datetime
3 |
4 |
5 | def get_feed():
6 | to_date = datetime.datetime.now()
7 | from_date = to_date - datetime.timedelta(days=1)
8 | posts = api_instance.get_posts(from_date, to_date)
9 | return posts
10 |
--------------------------------------------------------------------------------
/Chapter_3/Post.py:
--------------------------------------------------------------------------------
1 | from dataclasses import dataclass
2 | import datetime
3 |
4 |
5 | @dataclass(init=True)
6 | class Post:
7 | creator_name: str
8 | content: str
9 | posting_date: datetime.datetime
10 |
--------------------------------------------------------------------------------
/Chapter_3/Views-__init__.py:
--------------------------------------------------------------------------------
1 | from .AddPostView import AddPostView
2 | from .FeedView import FeedView
3 |
--------------------------------------------------------------------------------
/Chapter_3/config.toml:
--------------------------------------------------------------------------------
1 | [theme]
2 |
3 | base = 'light'
4 | primaryColor = '#7792E3'
5 | backgroundColor = '#273346'
6 | secondaryBackgroundColor = '#B9F1C0'
7 | textColor = '#FFFFFF'
8 | font = 'sans serif'
9 |
--------------------------------------------------------------------------------
/Chapter_3/footer.py:
--------------------------------------------------------------------------------
1 | st.sidebar.markdown(
2 | f'''
3 |
Hello world v 0.1
4 |
Hello world LLC.
''',
5 | unsafe_allow_html=True)
6 |
--------------------------------------------------------------------------------
/Chapter_3/main.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from Views import FeedView, AddPostView
3 | from Services import get_feed, add_post
4 |
5 | AddPostView(add_post)
6 | st.write("___")
7 | FeedView(get_feed)
8 |
9 |
--------------------------------------------------------------------------------
/Chapter_3/main_page.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from pages.page_1 import func_page_1
3 | from pages.page_2 import func_page_2
4 |
5 | def main():
6 |
7 | st.sidebar.subheader('Page selection')
8 | page_selection = st.sidebar.selectbox('Please select a page',['Main Page','Page 1','Page 2'])
9 |
10 | pages_main = {
11 | 'Main Page': main_page,
12 | 'Page 1': run_page_1,
13 | 'Page 2': run_page_2
14 | }
15 |
16 | # Run selected page
17 | pages_main[page_selection]()
18 |
19 | def main_page():
20 | st.title('Main Page')
21 |
22 | def run_page_1():
23 | func_page_1()
24 |
25 | def run_page_2():
26 | func_page_2()
27 |
28 | if __name__ == '__main__':
29 | main()
30 |
--------------------------------------------------------------------------------
/Chapter_3/main_page_subpage.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from pages.page_1 import func_page_1
3 | from pages.subpages_1.subpage_1_1 import func_subpage_1_1
4 | from pages.subpages_1.subpage_1_2 import func_subpage_1_2
5 |
6 | def main():
7 |
8 | st.sidebar.subheader('Page selection')
9 | page_selection = st.sidebar.selectbox('Please select a page',['Main Page','Page 1'])
10 |
11 | pages_main = {
12 | 'Main Page': main_page,
13 | 'Page 1': run_page_1
14 | }
15 |
16 | subpages_page_1 = {
17 | 'Subpage 1.1': run_subpage_1_1,
18 | 'Subpage 1.2': run_subpage_1_2
19 | }
20 |
21 | if page_selection == 'Main':
22 | # Run selected page
23 | pages_main[page_selection]()
24 |
25 | elif page_selection == 'Page 1':
26 | st.sidebar.subheader('Subpage selection')
27 | subpage_selection_1 = st.sidebar.selectbox("Please select a subpage", tuple(subpages_page_1.keys()))
28 | # Run selected subpage
29 | subpages_page_1[subpage_selection_1]()
30 |
31 | def main_page():
32 | st.title('Main Page')
33 |
34 | def run_page_1():
35 | func_page_1()
36 |
37 | def run_subpage_1_1():
38 | func_subpage_1_1()
39 |
40 | def run_subpage_1_2():
41 | func_subpage_1_2()
42 |
43 | if __name__ == '__main__':
44 | main()
45 |
--------------------------------------------------------------------------------
/Chapter_3/page_1.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | def func_page_1():
4 | st.title('Page 1')
5 |
--------------------------------------------------------------------------------
/Chapter_3/page_2.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | def func_page_2():
4 | st.title('Page 2')
5 |
--------------------------------------------------------------------------------
/Chapter_3/page_config.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from PIL import Image
3 | icon = Image.open('favicon.ico')
4 |
5 | st.set_page_config(
6 | page_title='Hello world',
7 | page_icon=icon,
8 | layout='centered',
9 | initial_sidebar_state='auto',
10 | menu_items={
11 | 'Get Help': 'https://streamlit.io/',
12 | 'Report a bug': 'https://github.com',
13 | 'About': 'About your application: **Hello world**'
14 | }
15 | )
16 |
17 | st.sidebar.title('Hello world')
18 | st.title('Hello world')
19 |
--------------------------------------------------------------------------------
/Chapter_3/page_organization.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from datetime import datetime
3 |
4 | #Expander in sidebar
5 | st.sidebar.subheader('Expander')
6 | with st.sidebar.expander('Time'):
7 | time = datetime.now().strftime("%H:%M:%S")
8 | st.write('**%s**' % (time))
9 |
10 | #Columns in sidebar
11 | st.sidebar.subheader('Columns')
12 | col1, col2 = st.sidebar.columns(2)
13 | with col1:
14 | option_1 = st.selectbox('Please select option 1',['A','B'])
15 | with col2:
16 | option_2 = st.radio('Please select option 2',['A','B'])
17 |
18 | #Container in sidebar
19 | container = st.sidebar.container()
20 | container.subheader('Container')
21 | option_3 = container.slider('Please select option 3')
22 | st.sidebar.warning('Elements outside of container will be displayed externally')
23 | container.info('**Option 3:** %s' % (option_3))
24 |
25 | #Expander in main body
26 | st.subheader('Expander')
27 | with st.expander('Time'):
28 | time = datetime.now().strftime("%H:%M:%S")
29 | st.write('**%s**' % (time))
30 |
31 | #Columns in main body
32 | st.subheader('Columns')
33 | col1, col2 = st.columns(2)
34 | with col1:
35 | option_4 = st.selectbox('Please select option 4',['A','B'])
36 | with col2:
37 | option_5 = st.radio('Please select option 5',['A','B'])
38 |
39 | #Container in main body
40 | container = st.container()
41 | container.subheader('Container')
42 | option_6 = container.slider('Please select option 6')
43 | st.warning('Elements outside of container will be displayed externally')
44 | container.info('**Option 6:** %s' % (option_6))
45 |
--------------------------------------------------------------------------------
/Chapter_3/placeholder.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from datetime import datetime
3 |
4 | st.title('Clock')
5 | clock = st.empty()
6 |
7 | while True:
8 | time = datetime.now().strftime("%H:%M:%S")
9 | clock.info('**Current time: ** %s' % (time))
10 |
11 | if time == '16:09:50':
12 | clock.empty()
13 | st.warning('Alarm!!')
14 | break
15 |
--------------------------------------------------------------------------------
/Chapter_3/progress_bar.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import wget
3 |
4 | progress_text = st.empty()
5 | progress_bar = st.progress(0)
6 |
7 | def streamlit_progress_bar(current,total,width):
8 | percent = int((current/total)*100)
9 | progress_text.subheader('Progress: {}%'.format(percent))
10 | progress_bar.progress(percent)
11 |
12 | wget.download('file URL',
13 | bar=streamlit_progress_bar)
14 |
--------------------------------------------------------------------------------
/Chapter_3/remove_footer_menu.py:
--------------------------------------------------------------------------------
1 | hide_footer_style = '''
2 |
11 | '''
12 |
13 | st.markdown(hide_menu_style, unsafe_allow_html=True)
14 |
--------------------------------------------------------------------------------
/Chapter_3/subpage_1_1.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | def func_subpage_1_1():
4 | st.title('Subpage 1.1')
5 |
--------------------------------------------------------------------------------
/Chapter_3/subpage_1_2.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 | def func_subpage_1_2():
4 | st.title('Subpage 1.2')
5 |
--------------------------------------------------------------------------------
/Chapter_5/df_demo.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import pandas as pd
3 |
4 | df = pd.DataFrame([["Adam", "01/01/1990", 2],
5 | ["Sara", "01/01/1980", 1],
6 | ["Bob", "01/01/1970", 1],
7 | ["Alice", "01/01/2000", 3]
8 | ], columns=["Name", "DOB", "Paygrade ID"])
9 |
10 | st.table(df)
11 |
12 | st.dataframe(df)
--------------------------------------------------------------------------------
/Chapter_5/main.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import psycopg2
3 |
4 |
5 | @st.cache(allow_output_mutation=True,
6 | hash_funcs={"_thread.RLock": lambda _: None})
7 | def init_connection():
8 | return psycopg2.connect(**st.secrets["db_postrgres"])
9 |
10 |
11 | conn = init_connection()
12 |
13 |
14 | def run_query(query_str):
15 | cur = conn.cursor()
16 | cur.execute(query_str)
17 | data = cur.fetchall()
18 | cur.close()
19 | return data
20 |
21 |
22 | def run_query_with_context_manager(query_str):
23 | with conn.cursor() as cur:
24 | cur.execute(query_str)
25 | return cur.fetchall()
26 |
27 |
28 | query = st.text_input("Query")
29 |
30 | c1, c2 = st.columns(2)
31 |
32 | output = None
33 |
34 | with c1:
35 | if st.button("Run with context manager"):
36 | output = run_query_with_context_manager(query)
37 | with c2:
38 | if st.button("Run without context manager"):
39 | output = run_query(query)
40 |
41 | st.write(output)
42 |
43 |
--------------------------------------------------------------------------------
/Chapter_5/secrets.toml:
--------------------------------------------------------------------------------
1 | [db_postrgres]
2 | host = "127.0.0.1"
3 | port = "5432"
4 | user = "postgres"
5 | password = "admin"
6 | dbname = "CompanyData"
--------------------------------------------------------------------------------
/Chapter_6/Base.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy.ext.declarative import declarative_base
2 |
3 | Base = declarative_base()
4 |
--------------------------------------------------------------------------------
/Chapter_6/Employees.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Column, Integer, String
2 | from .Base import Base
3 |
4 |
5 | class Employees(Base):
6 | __tablename__ = 'persons'
7 | id = Column(Integer, primary_key=True)
8 |
9 | name = Column(String)
10 | date_of_birth = Column(String, default=True)
11 | paygrade_id = Column(Integer, unique=True, index=True)
12 |
13 | def to_dict(self):
14 | return {
15 | "id": self.id,
16 | "name": self.name,
17 | "date_of_birth": self.date_of_birth,
18 | "paygrade_id": self.paygrade_id
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter_6/PayGrades.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Column, Integer, String
2 | from .Base import Base
3 |
4 |
5 | class PayGrades(Base):
6 | __tablename__ = 'paygrades'
7 | id = Column(Integer, primary_key=True)
8 |
9 | base_salary = Column(String)
10 | reimbursement = Column(String, default=True)
11 | bonuses = Column(String)
12 |
13 | def to_dict(self):
14 | return {
15 | "id": self.id,
16 | "base_salary": self.base_salary,
17 | "reimbursement": self.reimbursement,
18 | "bonuses": self.bonuses
19 | }
20 |
--------------------------------------------------------------------------------
/Chapter_6/flask_sample.py:
--------------------------------------------------------------------------------
1 | from flask import Flask
2 |
3 | app = Flask(__name__)
4 |
5 |
6 | @app.route('/server_status')
7 | def welcome_controller():
8 | return {
9 | "message": "Welcome to your Flask Server",
10 | "status": "up",
11 | "random": 1 + 1
12 | }
13 |
14 |
15 | app.run()
16 |
--------------------------------------------------------------------------------
/Chapter_6/main.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request
2 | from DataBase import Connection
3 | from DataBase import Employees
4 |
5 | app = Flask(__name__)
6 |
7 |
8 | @app.route('/employees')
9 | def get_all_employees():
10 | with connection.use_session() as session:
11 | employees = session.query(Employees).all()
12 | employees = [employee.to_dict() for employee in employees]
13 | return {"data": employees}
14 |
15 |
16 | @app.route('/employee', methods=["POST"])
17 | def add_employee():
18 | body = request.json
19 | with connection.use_session() as session:
20 | session.add(Employees(**body))
21 | session.commit()
22 | return {"message": "New employee added successfully"}
23 |
24 |
25 | connection = Connection("postgresql://postgres:admin@127.0.0.1:5432/CompanyData")
26 | app.run()
27 |
--------------------------------------------------------------------------------
/Chapter_6/sample_json.json:
--------------------------------------------------------------------------------
1 | [
2 | {
3 | "Name": "Adam",
4 | "DOB": "01/01/1990",
5 | "Paygrade ID": "2"
6 | },
7 | {
8 | "Name": "Sara",
9 | "DOB": "01/01/1980",
10 | "Paygrade ID": "1"
11 | },
12 | {
13 | "Name": "Bob",
14 | "DOB": "01/01/1970",
15 | "Paygrade ID": "1"
16 | },
17 | {
18 | "Name": "Alice",
19 | "DOB": "01/01/2000",
20 | "Paygrade ID": "3"
21 | }
22 | ]
--------------------------------------------------------------------------------
/Chapter_6/streamlit_api.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import requests
3 | import datetime
4 |
5 | url = "http://127.0.0.1:5000"
6 |
7 |
8 | def add_employee(name, dob, paygrade):
9 | data = {
10 | "name": name,
11 | "date_of_birth": dob,
12 | "paygrade_id": paygrade
13 | }
14 | response = requests.post(url + "/employee", json=data)
15 | if response.status_code == 200:
16 | return True
17 | return False
18 |
19 |
20 | def get_employees():
21 | response = requests.get(url + "/employees")
22 | return response.json()['data']
23 |
24 |
25 | form = st.form("new_employee")
26 | name = form.text_input("Name")
27 | dob = str(form.date_input("DOB", min_value=datetime.datetime(year=1920, day=1, month=1)))
28 | paygrade = form.number_input("paygrade", step=1)
29 |
30 | if form.form_submit_button("Add new Employee"):
31 | if add_employee(name, dob, paygrade):
32 | st.success("Employee Added")
33 | else:
34 | st.error("Error adding employee")
35 |
36 | st.write("___")
37 |
38 | employees = get_employees()
39 | st.table(employees)
40 |
--------------------------------------------------------------------------------
/Chapter_6/streamlit_main.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from multiprocessing import Pool, cpu_count
3 | import threading
4 | import time
5 |
6 |
7 | def func(iterations, id):
8 | i = 0
9 | for i in range(iterations):
10 | i += 1
11 | print("Finished job id =", id)
12 |
13 |
14 | if __name__ == "__main__":
15 | pool = Pool(cpu_count())
16 |
17 | st.title("Speed You Code!")
18 |
19 | jobs_count = 5
20 | iterations = 10 ** 3
21 | c1, c2 = st.columns(2)
22 |
23 | with c1:
24 | if st.button("multiprocess"):
25 | inputs = [(iterations, i) for i in range(jobs_count)]
26 | t11 = time.time()
27 | pool.starmap(func, inputs)
28 | t21 = time.time()
29 | st.write(f"Finished after {t21 - t11} seconds")
30 | with c2:
31 | if st.button("multithread"):
32 | threads = [threading.Thread(target=func, args=(iterations, i)) for i in range(10)]
33 |
34 | t12 = time.time()
35 | for thread in threads:
36 | thread.start()
37 | for thread in threads:
38 | thread.join()
39 | t22 = time.time()
40 | st.write(f"Finished after {t22 - t12} seconds")
41 |
--------------------------------------------------------------------------------
/Chapter_7/cookie_management.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | import extra_streamlit_components as stx
3 |
4 | st.title("Cookie Management Demo")
5 | st.subheader("_Featuring Cookie Manager from Extra-Streamlit-Components_")
6 |
7 | cookie_manager = stx.CookieManager()
8 |
9 | st.subheader("All Cookies:")
10 | cookies = cookie_manager.get_all()
11 | st.write(cookies)
12 |
13 | c1, c2, c3 = st.columns(3)
14 | with c1:
15 | st.subheader("Get Cookie:")
16 | cookie = st.text_input("Cookie", key="0")
17 | clicked = st.button("Get")
18 | if clicked:
19 | value = cookie_manager.get(cookie)
20 | st.write(value)
21 | with c2:
22 | st.subheader("Set Cookie:")
23 | cookie = st.text_input("Cookie", key="1")
24 | val = st.text_input("Value")
25 | if st.button("Add"):
26 | cookie_manager.set(cookie, val)
27 | with c3:
28 | st.subheader("Delete Cookie:")
29 | cookie = st.text_input("Cookie", key="2")
30 | if st.button("Delete"):
31 | cookie_manager.delete(cookie)
32 |
--------------------------------------------------------------------------------
/Chapter_7/session_id_demo.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from streamlit.report_thread import get_report_ctx
3 | from streamlit.server.server import Server
4 |
5 | all_sessions = Server.get_current()._session_info_by_id
6 |
7 | session_id = get_report_ctx().session_id
8 | session_number = list(all_sessions.keys()).index(session_id) + 1
9 |
10 | st.title("Session ID #"+str(session_number))
11 | st.header("Id of this session is: " + session_id)
12 | st.subheader("All sessions ("+str(len(all_sessions))+") :")
13 | st.write(all_sessions)
14 |
--------------------------------------------------------------------------------
/Chapter_7/session_state.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 |
3 |
4 | def get_state_value(key):
5 | return st.session_state.get(key)
6 |
7 |
8 | def set_state_value(key, value):
9 | st.session_state[key] = value
10 |
11 |
12 | st.title("Session State Management")
13 | c1, c2, c3 = st.columns(3)
14 |
15 | with c1:
16 | st.subheader("All")
17 | st.write(st.session_state)
18 | with c2:
19 | st.subheader("Set Key")
20 | key = st.text_input("Key", key="KeyInput1")
21 | value = st.text_input("Value")
22 |
23 | if st.button("Set"):
24 | st.session_state[key] = value
25 | st.success("Success")
26 | with c3:
27 | st.subheader("Get Key")
28 | key = st.text_input("Key", key="KeyInput2")
29 |
30 | if st.button("Get"):
31 | st.write(st.session_state.get(key))
32 |
--------------------------------------------------------------------------------
/Chapter_8/.gitignore:
--------------------------------------------------------------------------------
1 | secrets.yaml
--------------------------------------------------------------------------------
/Chapter_8/API.py:
--------------------------------------------------------------------------------
1 | import requests
2 |
3 |
4 | class API:
5 | def __init__(self, base_url: str, token: str):
6 | self.base_url = base_url
7 | self.base_headers = {"token": token}
8 |
9 | def add_employee(self, name, dob, paygrade):
10 | try:
11 | data = {
12 | "name": name,
13 | "date_of_birth": dob,
14 | "paygrade_id": paygrade
15 | }
16 | response = requests.post(self.base_url + "/employee",
17 | json=data, headers=self.base_headers)
18 | if response.status_code == 200:
19 | return True
20 | except:
21 | return False
22 |
23 | def get_employees(self):
24 | try:
25 | response = requests.get(self.base_url + "/employees",
26 | headers=self.base_headers)
27 | return response.json()['data']
28 | except:
29 | return None
30 |
31 | def login(self, username, password):
32 | try:
33 | response = requests.post(self.base_url + "/auth/login", json={
34 | "username": username,
35 | "password": password
36 | })
37 | body = response.json()
38 | token = body.get("token") if type(body) == dict else None
39 |
40 | return token
41 | except:
42 | return None
43 |
44 | def is_logged_in(self):
45 | return requests.get(self.base_url + "/auth/is_logged_in",
46 | headers=self.base_headers).status_code == 200
47 |
--------------------------------------------------------------------------------
/Chapter_8/AddEmployee.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from typing import Callable
3 | import datetime
4 |
5 |
6 | class AddEmployee:
7 | def __init__(self, on_submit: Callable[[str, str, int], bool]):
8 | st.header("Add a new employee")
9 |
10 | form = st.form("new_employee")
11 | name = form.text_input("Name")
12 | dob = str(form.date_input("DOB",
13 | min_value=datetime.datetime(year=1920, day=1, month=1)))
14 | paygrade = form.number_input("paygrade", step=1)
15 |
16 | if form.form_submit_button("Add new Employee"):
17 | success = on_submit(name, dob, paygrade)
18 | if success:
19 | st.success("New employee added")
20 | else:
21 | st.error("Employee not added")
22 |
--------------------------------------------------------------------------------
/Chapter_8/Admins.py:
--------------------------------------------------------------------------------
1 | from sqlalchemy import Column, Integer, String
2 | from .Base import Base
3 |
4 |
5 | class Admins(Base):
6 | __tablename__ = 'admins'
7 | id = Column(Integer, primary_key=True)
8 |
9 | username = Column(String)
10 | password_hash = Column(String, default=True)
11 |
12 | def to_dict(self):
13 | return {
14 | "id": self.id,
15 | "username": self.username,
16 | "password_hash": self.password_hash
17 | }
18 |
--------------------------------------------------------------------------------
/Chapter_8/DisplayEmployees.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from typing import Callable
3 |
4 |
5 | class DisplayEmployees:
6 | def __init__(self, get_employees: Callable[[], list]):
7 | st.header("Current Employees")
8 |
9 | employees = get_employees()
10 |
11 | if employees is None:
12 | st.error("Error getting employees")
13 | else:
14 | st.table(employees)
15 |
--------------------------------------------------------------------------------
/Chapter_8/HashingService.py:
--------------------------------------------------------------------------------
1 | import bcrypt
2 |
3 |
4 | class HashingService:
5 | def __init__(self, bcrypt_gen_salt: int = 12):
6 | self.gen_salt = bcrypt_gen_salt
7 |
8 | def hash_bcrypt(self, plain_text: bytes) -> bytes:
9 | return bcrypt.hashpw(plain_text, bcrypt.gensalt(self.gen_salt))
10 |
11 | def check_bcrypt(self, plain_text: bytes, hashed_password: bytes) -> bool:
12 | try:
13 | return bcrypt.checkpw(plain_text, hashed_password)
14 | except:
15 | return False
16 |
--------------------------------------------------------------------------------
/Chapter_8/JWTService.py:
--------------------------------------------------------------------------------
1 | from jwt import PyJWT
2 | from time import time
3 | from typing import Union
4 |
5 |
6 | class JWTService:
7 | expires_in_seconds = 2592000
8 | signing_algorithm = "HS256"
9 |
10 | def __init__(self, signing_key: str, expires_in_seconds: int = 2592000):
11 | self.signing_key = signing_key
12 | self.expires_in_seconds = expires_in_seconds
13 |
14 | def generate(self, data: dict, expires_in_seconds: int = expires_in_seconds) -> Union[str, None]:
15 | try:
16 | instance = PyJWT()
17 |
18 | curr_unix_epoch = int(time())
19 | data['iat'] = curr_unix_epoch
20 |
21 | if isinstance(expires_in_seconds, int):
22 | data['exp'] = curr_unix_epoch + expires_in_seconds
23 |
24 | token = instance.encode(payload=data, key=self.signing_key, algorithm=self.signing_algorithm)
25 |
26 | if type(token) == bytes:
27 | token = token.decode('utf8') # Needed for some versions of PyJWT
28 |
29 | return token
30 | except BaseException as _:
31 | return None
32 |
33 | def is_valid(self, token: str, verify_time: bool = True) -> bool:
34 | try:
35 | payload = self.get_payload(token)
36 |
37 | if payload is None:
38 | return False
39 |
40 | if verify_time and 'exp' in payload and payload['exp'] < int(time()):
41 | return False
42 |
43 | return True
44 | except:
45 | return False
46 |
47 | def get_payload(self, token: str):
48 | try:
49 | instance = PyJWT()
50 | payload = instance.decode(jwt=token, key=self.signing_key, algorithms=[self.signing_algorithm])
51 | return payload
52 | except Exception as e:
53 | print(e)
54 | return None
55 |
--------------------------------------------------------------------------------
/Chapter_8/Login.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from typing import Callable
3 |
4 |
5 | class Login:
6 | def __init__(self, on_login: Callable[[str, str], bool]):
7 | st.header("Login")
8 | username = st.text_input("Username")
9 | password = st.text_input("Password",type="password")
10 |
11 | if st.button("Login"):
12 | success = on_login(username, password)
13 | if success:
14 | st.success("Login successful")
15 | else:
16 | st.error("Incorrect username and password combination")
17 |
--------------------------------------------------------------------------------
/Chapter_8/Middleware.py:
--------------------------------------------------------------------------------
1 | from flask import Request
2 | from Services.JWTService import JWTService
3 | from werkzeug import exceptions
4 |
5 |
6 | class Middleware:
7 | def __init__(self, jwt_service: JWTService):
8 | self.unauthenticated_route_names = {"/api/auth/login", "/api/auth/sing_up"}
9 | self.jwt_service = jwt_service
10 |
11 | def auth(self, request: Request):
12 | is_route_unauthenticated = request.path in self.unauthenticated_route_names
13 |
14 | if is_route_unauthenticated:
15 | return None
16 |
17 | if "token" in request.headers:
18 | token = request.headers['token']
19 | is_valid = self.jwt_service.is_valid(token)
20 | if is_valid:
21 | return None
22 | else:
23 | return exceptions.Unauthorized()
24 |
25 | return exceptions.Unauthorized()
26 |
--------------------------------------------------------------------------------
/Chapter_8/flask_main.py:
--------------------------------------------------------------------------------
1 | from flask import Flask, request
2 | from DataBase import Connection, Employees, Admins
3 | from Services import JWTService, HashingService
4 | from Middleware import Middleware
5 | from werkzeug import exceptions
6 | import yaml
7 |
8 | app = Flask(__name__)
9 |
10 | with open("secrets.yaml") as f:
11 | yaml_dict = yaml.safe_load(f)
12 | sing_up_key = yaml_dict['sing_up_key']
13 | jwt_secret = yaml_dict['jwt_secret']
14 |
15 | jwt_service = JWTService(jwt_secret)
16 | middleware = Middleware(jwt_service)
17 | hashing_service = HashingService()
18 |
19 | app.before_request(lambda: middleware.auth(request))
20 |
21 |
22 | @app.route('/api/employees')
23 | def get_all_employees():
24 | with connection.use_session() as session:
25 | employees = session.query(Employees).all()
26 | employees = [employee.to_dict() for employee in employees]
27 | return {"data": employees}
28 |
29 |
30 | @app.route('/api/employee', methods=["POST"])
31 | def add_employee():
32 | body = request.json
33 | with connection.use_session() as session:
34 | session.add(Employees(**body))
35 | session.commit()
36 | return {"message": "New employee added successfully"}
37 |
38 |
39 | @app.route('/api/auth/login', methods=["POST"])
40 | def log_in():
41 | username, password = request.json['username'], request.json['password']
42 | with connection.use_session() as session:
43 | admin_account = session.query(Admins).filter(
44 | Admins.username == username).first()
45 | if admin_account is None:
46 | # Username doesn't exist. But don't inform the client with that as
47 | # they can use it to bruteforce valid usernames
48 | return exceptions.Unauthorized(
49 | description="Incorrect username/password combination")
50 |
51 | # Checking if such hash can be generated from that password
52 | is_password_correct = hashing_service.check_bcrypt(
53 | password.encode("utf8"), admin_account.password_hash.encode("utf8"))
54 | if not is_password_correct:
55 | return exceptions.Unauthorized(
56 | description="Incorrect username/password combination")
57 |
58 | token_payload = {"username": username}
59 | token = jwt_service.generate(token_payload)
60 |
61 | if token is None:
62 | return exceptions.InternalServerError(description="Login failed")
63 |
64 | return {"token": token}
65 |
66 |
67 | @app.route('/api/auth/sing_up', methods=["POST"])
68 | def sign_up():
69 | username, password = request.json['username'], request.json['password']
70 | if request.headers.get("sing_up_key") != "sing_up_key":
71 | exceptions.Unauthorized(description="Incorrect Key")
72 |
73 | with connection.use_session() as session:
74 | password_hash = hashing_service.hash_bcrypt(
75 | password.encode("utf-8")).decode("utf-8")
76 | admin = Admins(username=username, password_hash=password_hash)
77 | session.add(admin)
78 | session.commit()
79 | return {"message": "Admin account created successfully"}
80 |
81 |
82 | @app.route('/api/auth/is_logged_in')
83 | def is_logged_in():
84 | # If this controller is reached this means the
85 | # Auth middleware recognizes the passed token
86 | return {"message": "Token is valid"}
87 |
88 |
89 | connection = Connection("postgresql://postgres:admin@127.0.0.1:5432/CompanyData")
90 | app.run()
91 |
--------------------------------------------------------------------------------
/Chapter_8/secrets.example.yaml:
--------------------------------------------------------------------------------
1 | # Copy the content of this file to secrets.yaml
2 | # and replace its contents with the correct values
3 | jwt_secret: ""
4 | sing_up_key: ""
--------------------------------------------------------------------------------
/Chapter_8/streamlit_main.py:
--------------------------------------------------------------------------------
1 | import streamlit as st
2 | from Views import AddEmployee, DisplayEmployees, Login
3 | from API import API
4 | import extra_streamlit_components as stx
5 | import base64, json
6 |
7 | cookie_manager = stx.CookieManager()
8 | cookies = cookie_manager.get_all()
9 | authentication_token = cookies.get("token")\
10 | if type(cookies) == dict else cookies
11 |
12 | api = API("http://127.0.0.1:5000/api", authentication_token)
13 |
14 |
15 | def get_username_from_token(auth_token):
16 | b64 = str(auth_token).split(".")[1]
17 | b64 = b64 + "=" * (4 - (len(b64) % 4))
18 | data = base64.b64decode(b64).decode("utf8")
19 | username = json.loads(data)['username']
20 | return username
21 |
22 |
23 | def manage_login(username, password):
24 | token = api.login(username, password)
25 | cookie_manager.set("token", token)
26 | return token is not None
27 |
28 |
29 | st.title("Company Management Portal")
30 |
31 | if api.is_logged_in():
32 | st.subheader(f"_Welcome "
33 | f"**{get_username_from_token(authentication_token)}**_")
34 | st.write("_____")
35 | AddEmployee(api.add_employee)
36 | st.write("___")
37 | DisplayEmployees(api.get_employees)
38 | else:
39 | Login(manage_login)
40 |
--------------------------------------------------------------------------------
/Contributing.md:
--------------------------------------------------------------------------------
1 | # Contributing to Apress Source Code
2 |
3 | Copyright for Apress source code belongs to the author(s). However, under fair use you are encouraged to fork and contribute minor corrections and updates for the benefit of the author(s) and other readers.
4 |
5 | ## How to Contribute
6 |
7 | 1. Make sure you have a GitHub account.
8 | 2. Fork the repository for the relevant book.
9 | 3. Create a new branch on which to make your change, e.g.
10 | `git checkout -b my_code_contribution`
11 | 4. Commit your change. Include a commit message describing the correction. Please note that if your commit message is not clear, the correction will not be accepted.
12 | 5. Submit a pull request.
13 |
14 | Thank you for your contribution!
--------------------------------------------------------------------------------
/LICENSE.txt:
--------------------------------------------------------------------------------
1 | Freeware License, some rights reserved
2 |
3 | Copyright (c) 2022 Rishabh Jain
4 |
5 | Permission is hereby granted, free of charge, to anyone obtaining a copy
6 | of this software and associated documentation files (the "Software"),
7 | to work with the Software within the limits of freeware distribution and fair use.
8 | This includes the rights to use, copy, and modify the Software for personal use.
9 | Users are also allowed and encouraged to submit corrections and modifications
10 | to the Software for the benefit of other users.
11 |
12 | It is not allowed to reuse, modify, or redistribute the Software for
13 | commercial use in any way, or for a user’s educational materials such as books
14 | or blog articles without prior permission from the copyright holder.
15 |
16 | The above copyright notice and this permission notice need to be included
17 | in all copies or substantial portions of the software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22 | AUTHORS OR COPYRIGHT HOLDERS OR APRESS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
25 | SOFTWARE.
26 |
27 |
28 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # Apress Source Code
2 |
3 | This repository accompanies [*Web Application Development with Streamlit: Develop and Deploy Secure and Scalable Web Applications to the Cloud Using a Pure Python Framework*](https://www.link.springer.com/book/10.1007/9781484281109) by Mohammad Khorasani, Mohamed Abdou, Javier Hernandez Fernandez (Apress, 2022).
4 |
5 | [comment]: #cover
6 | 
7 |
8 | Download the files as a zip using the green button, or clone the repository to your machine using Git.
9 |
10 | ## Releases
11 |
12 | Release v1.0 corresponds to the code in the published book, without corrections or updates.
13 |
14 | ## Contributions
15 |
16 | See the file Contributing.md for more information on how you can contribute to this repository.
--------------------------------------------------------------------------------