pumpwood_streamlit.dashboard

Dashboard class to use as base from Pumpwood Streamlit Dashboards.

  1"""Dashboard class to use as base from Pumpwood Streamlit Dashboards."""
  2import os
  3import streamlit as st
  4import extra_streamlit_components as stx
  5from abc import ABC, abstractmethod
  6from pumpwood_communication.microservices import PumpWoodMicroService
  7
  8
  9def _get_cookie_manager():
 10    """Retrieve Cookie Manager."""
 11    return stx.CookieManager()
 12
 13
 14class PumpwoodStreamlitDashboard(ABC):
 15    """Abstract Class to facilitate criation of Streamlit Dashboards."""
 16
 17    def __init__(self, microservice: PumpWoodMicroService = None):
 18        """
 19        __init__.
 20
 21        It is possible to init object with a microservice to help
 22        building dashboard.
 23
 24        If microservice=None (production deploy), `__init__` will create an
 25        unlogged microservice object using `MICROSERVICE_URL` from enviroment
 26        variable. Authentication validation function will set attribute
 27        `_auth_token` with `PumpwoodAuthorization` token that can be used
 28        to user impersonation.
 29
 30        Args:
 31            microservice:
 32                 An microservice can be passed to object for developing
 33                 and debug.
 34        """
 35        # Set auth_header to None, this will permit dev microservice to
 36        # use credencials and prod get auth header from cookie
 37        self._auth_token = None
 38        if microservice is not None:
 39            self._microservice = microservice
 40        else:
 41            MICROSERVICE_URL = os.getenv("MICROSERVICE_URL")
 42            if MICROSERVICE_URL is not None:
 43                self._microservice = PumpWoodMicroService(
 44                    name="dashboard-microservice",
 45                    server_url=MICROSERVICE_URL)
 46            else:
 47                msg = (
 48                    "'microservice' is not set as argument and " +
 49                    "'MICROSERVICE_URL' not set as enviroment variable")
 50                raise Exception(msg)
 51
 52    def validate_authentication(self) -> bool:
 53        """
 54        Validate authentication using cookie with PumpwoodAuthorization.
 55
 56        Returns:
 57            Return True if user is logged on Pumpwood and False if token
 58            set at PumpwoodAuthorization is invalid.
 59        """
 60        cookie_manager = _get_cookie_manager()
 61        cookie_auth_token = cookie_manager.get('PumpwoodAuthorization')
 62        if cookie_auth_token is not None:
 63            self._auth_token = {"Authorization": 'Token ' + cookie_auth_token}
 64
 65        is_logged = self._microservice.check_if_logged(
 66            auth_header=self._auth_token)
 67        return is_logged
 68
 69    def authentication_error_page(self) -> None:
 70        """
 71        Set the authentication error page.
 72
 73        This function is called if self.validate_login() return False.
 74
 75        Example:
 76        ```python
 77        st.title('User token is invalid, log in again to refresh token.')
 78        ```
 79        """
 80        st.title('User token is invalid, log in again to refresh token.')
 81
 82    def run(self) -> None:
 83        """
 84        Render Streamlit dashboard.
 85
 86        This function is used as an entry point for app.py Streamlit
 87        dashboard.
 88
 89        Most of the cases should not be reimplemented. It is important
 90        that if reimplemented `is_logged = self.validate_authentication()`
 91        function must be called at the beggin to assure that user is
 92        authenticated on Pumpwood.
 93
 94        Example of an app.py:
 95        ```
 96        import os
 97        from dashboard import Dashboard
 98        from pumpwood_communication.microservices import PumpWoodMicroService
 99
100        ###############################################################
101        # Read env variables to be used on local test of the dashboard.
102        # Passing a logged microservice to dashboard will disable
103        # authentication
104        # !!! DO NOT USE AUTHENTICATED MICROSERVICE IN PRODUCTION
105        # DASHBOARDS !!! #
106        MICROSERVICE_URL = os.getenv('MICROSERVICE_URL')
107        MICROSERVICE_DASHBOARD_USERNAME = os.getenv(
108            'MICROSERVICE_DASHBOARD_USERNAME')
109        MICROSERVICE_DASHBOARD_PASSWORD = os.getenv(
110            'MICROSERVICE_DASHBOARD_PASSWORD')
111
112        microservice = None
113        if MICROSERVICE_DASHBOARD_USERNAME is not None:
114            microservice = PumpWoodMicroService(
115                name="dashboard-microservice",
116                server_url=MICROSERVICE_URL,
117                username=MICROSERVICE_DASHBOARD_USERNAME,
118                password=MICROSERVICE_DASHBOARD_PASSWORD,)
119            microservice.login()
120
121        dash_obj = Dashboard(microservice=microservice)
122        dash_obj.run()
123        ```
124
125        Implemented run function:
126        ```python
127        def run(self) -> None:
128            # Set page configuration
129            self.set_page_config()
130
131            # Validate auth_header
132            is_logged = self.validate_authentication()
133            if not is_logged:
134                # Authorization error
135                self.authentication_error_page()
136            else:
137                # Render main Dashboard View
138                self.main_view()
139        ```
140        """
141        # Set page configuration
142        self.set_page_config()
143
144        # Validate auth_header
145        is_logged = self.validate_authentication()
146        if not is_logged:
147            # Authorization error
148            self.authentication_error_page()
149        else:
150            # Render main Dashboard View
151            self.main_view()
152
153    @abstractmethod
154    def set_page_config(self) -> None:
155        """
156        Set page config, must be implemented.
157
158        Exemple:
159        ```python
160        st.set_page_config(
161            page_title="US Population Dashboard",
162            page_icon="🏂",
163            layout="wide",
164            initial_sidebar_state="expanded")
165        ```
166        """
167        msg = "'set_page_config' function must be implemented"
168        raise NotImplementedError(msg)
169
170    @abstractmethod
171    def main_view(self) -> None:
172        """
173        Render main dashboard view.
174
175        Exemple:
176        ```python
177        st.set_page_config(
178            page_title="US Population Dashboard",
179            page_icon="🏂",
180            layout="wide",
181            initial_sidebar_state="expanded")
182        ```
183        """
184        msg = "'main_view' function must be implemented"
185        raise NotImplementedError(msg)
class PumpwoodStreamlitDashboard(abc.ABC):
 15class PumpwoodStreamlitDashboard(ABC):
 16    """Abstract Class to facilitate criation of Streamlit Dashboards."""
 17
 18    def __init__(self, microservice: PumpWoodMicroService = None):
 19        """
 20        __init__.
 21
 22        It is possible to init object with a microservice to help
 23        building dashboard.
 24
 25        If microservice=None (production deploy), `__init__` will create an
 26        unlogged microservice object using `MICROSERVICE_URL` from enviroment
 27        variable. Authentication validation function will set attribute
 28        `_auth_token` with `PumpwoodAuthorization` token that can be used
 29        to user impersonation.
 30
 31        Args:
 32            microservice:
 33                 An microservice can be passed to object for developing
 34                 and debug.
 35        """
 36        # Set auth_header to None, this will permit dev microservice to
 37        # use credencials and prod get auth header from cookie
 38        self._auth_token = None
 39        if microservice is not None:
 40            self._microservice = microservice
 41        else:
 42            MICROSERVICE_URL = os.getenv("MICROSERVICE_URL")
 43            if MICROSERVICE_URL is not None:
 44                self._microservice = PumpWoodMicroService(
 45                    name="dashboard-microservice",
 46                    server_url=MICROSERVICE_URL)
 47            else:
 48                msg = (
 49                    "'microservice' is not set as argument and " +
 50                    "'MICROSERVICE_URL' not set as enviroment variable")
 51                raise Exception(msg)
 52
 53    def validate_authentication(self) -> bool:
 54        """
 55        Validate authentication using cookie with PumpwoodAuthorization.
 56
 57        Returns:
 58            Return True if user is logged on Pumpwood and False if token
 59            set at PumpwoodAuthorization is invalid.
 60        """
 61        cookie_manager = _get_cookie_manager()
 62        cookie_auth_token = cookie_manager.get('PumpwoodAuthorization')
 63        if cookie_auth_token is not None:
 64            self._auth_token = {"Authorization": 'Token ' + cookie_auth_token}
 65
 66        is_logged = self._microservice.check_if_logged(
 67            auth_header=self._auth_token)
 68        return is_logged
 69
 70    def authentication_error_page(self) -> None:
 71        """
 72        Set the authentication error page.
 73
 74        This function is called if self.validate_login() return False.
 75
 76        Example:
 77        ```python
 78        st.title('User token is invalid, log in again to refresh token.')
 79        ```
 80        """
 81        st.title('User token is invalid, log in again to refresh token.')
 82
 83    def run(self) -> None:
 84        """
 85        Render Streamlit dashboard.
 86
 87        This function is used as an entry point for app.py Streamlit
 88        dashboard.
 89
 90        Most of the cases should not be reimplemented. It is important
 91        that if reimplemented `is_logged = self.validate_authentication()`
 92        function must be called at the beggin to assure that user is
 93        authenticated on Pumpwood.
 94
 95        Example of an app.py:
 96        ```
 97        import os
 98        from dashboard import Dashboard
 99        from pumpwood_communication.microservices import PumpWoodMicroService
100
101        ###############################################################
102        # Read env variables to be used on local test of the dashboard.
103        # Passing a logged microservice to dashboard will disable
104        # authentication
105        # !!! DO NOT USE AUTHENTICATED MICROSERVICE IN PRODUCTION
106        # DASHBOARDS !!! #
107        MICROSERVICE_URL = os.getenv('MICROSERVICE_URL')
108        MICROSERVICE_DASHBOARD_USERNAME = os.getenv(
109            'MICROSERVICE_DASHBOARD_USERNAME')
110        MICROSERVICE_DASHBOARD_PASSWORD = os.getenv(
111            'MICROSERVICE_DASHBOARD_PASSWORD')
112
113        microservice = None
114        if MICROSERVICE_DASHBOARD_USERNAME is not None:
115            microservice = PumpWoodMicroService(
116                name="dashboard-microservice",
117                server_url=MICROSERVICE_URL,
118                username=MICROSERVICE_DASHBOARD_USERNAME,
119                password=MICROSERVICE_DASHBOARD_PASSWORD,)
120            microservice.login()
121
122        dash_obj = Dashboard(microservice=microservice)
123        dash_obj.run()
124        ```
125
126        Implemented run function:
127        ```python
128        def run(self) -> None:
129            # Set page configuration
130            self.set_page_config()
131
132            # Validate auth_header
133            is_logged = self.validate_authentication()
134            if not is_logged:
135                # Authorization error
136                self.authentication_error_page()
137            else:
138                # Render main Dashboard View
139                self.main_view()
140        ```
141        """
142        # Set page configuration
143        self.set_page_config()
144
145        # Validate auth_header
146        is_logged = self.validate_authentication()
147        if not is_logged:
148            # Authorization error
149            self.authentication_error_page()
150        else:
151            # Render main Dashboard View
152            self.main_view()
153
154    @abstractmethod
155    def set_page_config(self) -> None:
156        """
157        Set page config, must be implemented.
158
159        Exemple:
160        ```python
161        st.set_page_config(
162            page_title="US Population Dashboard",
163            page_icon="🏂",
164            layout="wide",
165            initial_sidebar_state="expanded")
166        ```
167        """
168        msg = "'set_page_config' function must be implemented"
169        raise NotImplementedError(msg)
170
171    @abstractmethod
172    def main_view(self) -> None:
173        """
174        Render main dashboard view.
175
176        Exemple:
177        ```python
178        st.set_page_config(
179            page_title="US Population Dashboard",
180            page_icon="🏂",
181            layout="wide",
182            initial_sidebar_state="expanded")
183        ```
184        """
185        msg = "'main_view' function must be implemented"
186        raise NotImplementedError(msg)

Abstract Class to facilitate criation of Streamlit Dashboards.

PumpwoodStreamlitDashboard( microservice: pumpwood_communication.microservices.PumpWoodMicroService = None)
18    def __init__(self, microservice: PumpWoodMicroService = None):
19        """
20        __init__.
21
22        It is possible to init object with a microservice to help
23        building dashboard.
24
25        If microservice=None (production deploy), `__init__` will create an
26        unlogged microservice object using `MICROSERVICE_URL` from enviroment
27        variable. Authentication validation function will set attribute
28        `_auth_token` with `PumpwoodAuthorization` token that can be used
29        to user impersonation.
30
31        Args:
32            microservice:
33                 An microservice can be passed to object for developing
34                 and debug.
35        """
36        # Set auth_header to None, this will permit dev microservice to
37        # use credencials and prod get auth header from cookie
38        self._auth_token = None
39        if microservice is not None:
40            self._microservice = microservice
41        else:
42            MICROSERVICE_URL = os.getenv("MICROSERVICE_URL")
43            if MICROSERVICE_URL is not None:
44                self._microservice = PumpWoodMicroService(
45                    name="dashboard-microservice",
46                    server_url=MICROSERVICE_URL)
47            else:
48                msg = (
49                    "'microservice' is not set as argument and " +
50                    "'MICROSERVICE_URL' not set as enviroment variable")
51                raise Exception(msg)

__init__.

It is possible to init object with a microservice to help building dashboard.

If microservice=None (production deploy), __init__ will create an unlogged microservice object using MICROSERVICE_URL from enviroment variable. Authentication validation function will set attribute _auth_token with PumpwoodAuthorization token that can be used to user impersonation.

Arguments:
  • microservice: An microservice can be passed to object for developing and debug.
def validate_authentication(self) -> bool:
53    def validate_authentication(self) -> bool:
54        """
55        Validate authentication using cookie with PumpwoodAuthorization.
56
57        Returns:
58            Return True if user is logged on Pumpwood and False if token
59            set at PumpwoodAuthorization is invalid.
60        """
61        cookie_manager = _get_cookie_manager()
62        cookie_auth_token = cookie_manager.get('PumpwoodAuthorization')
63        if cookie_auth_token is not None:
64            self._auth_token = {"Authorization": 'Token ' + cookie_auth_token}
65
66        is_logged = self._microservice.check_if_logged(
67            auth_header=self._auth_token)
68        return is_logged

Validate authentication using cookie with PumpwoodAuthorization.

Returns:

Return True if user is logged on Pumpwood and False if token set at PumpwoodAuthorization is invalid.

def authentication_error_page(self) -> None:
70    def authentication_error_page(self) -> None:
71        """
72        Set the authentication error page.
73
74        This function is called if self.validate_login() return False.
75
76        Example:
77        ```python
78        st.title('User token is invalid, log in again to refresh token.')
79        ```
80        """
81        st.title('User token is invalid, log in again to refresh token.')

Set the authentication error page.

This function is called if self.validate_login() return False.

Example:

st.title('User token is invalid, log in again to refresh token.')
def run(self) -> None:
 83    def run(self) -> None:
 84        """
 85        Render Streamlit dashboard.
 86
 87        This function is used as an entry point for app.py Streamlit
 88        dashboard.
 89
 90        Most of the cases should not be reimplemented. It is important
 91        that if reimplemented `is_logged = self.validate_authentication()`
 92        function must be called at the beggin to assure that user is
 93        authenticated on Pumpwood.
 94
 95        Example of an app.py:
 96        ```
 97        import os
 98        from dashboard import Dashboard
 99        from pumpwood_communication.microservices import PumpWoodMicroService
100
101        ###############################################################
102        # Read env variables to be used on local test of the dashboard.
103        # Passing a logged microservice to dashboard will disable
104        # authentication
105        # !!! DO NOT USE AUTHENTICATED MICROSERVICE IN PRODUCTION
106        # DASHBOARDS !!! #
107        MICROSERVICE_URL = os.getenv('MICROSERVICE_URL')
108        MICROSERVICE_DASHBOARD_USERNAME = os.getenv(
109            'MICROSERVICE_DASHBOARD_USERNAME')
110        MICROSERVICE_DASHBOARD_PASSWORD = os.getenv(
111            'MICROSERVICE_DASHBOARD_PASSWORD')
112
113        microservice = None
114        if MICROSERVICE_DASHBOARD_USERNAME is not None:
115            microservice = PumpWoodMicroService(
116                name="dashboard-microservice",
117                server_url=MICROSERVICE_URL,
118                username=MICROSERVICE_DASHBOARD_USERNAME,
119                password=MICROSERVICE_DASHBOARD_PASSWORD,)
120            microservice.login()
121
122        dash_obj = Dashboard(microservice=microservice)
123        dash_obj.run()
124        ```
125
126        Implemented run function:
127        ```python
128        def run(self) -> None:
129            # Set page configuration
130            self.set_page_config()
131
132            # Validate auth_header
133            is_logged = self.validate_authentication()
134            if not is_logged:
135                # Authorization error
136                self.authentication_error_page()
137            else:
138                # Render main Dashboard View
139                self.main_view()
140        ```
141        """
142        # Set page configuration
143        self.set_page_config()
144
145        # Validate auth_header
146        is_logged = self.validate_authentication()
147        if not is_logged:
148            # Authorization error
149            self.authentication_error_page()
150        else:
151            # Render main Dashboard View
152            self.main_view()

Render Streamlit dashboard.

This function is used as an entry point for app.py Streamlit dashboard.

Most of the cases should not be reimplemented. It is important that if reimplemented is_logged = self.validate_authentication() function must be called at the beggin to assure that user is authenticated on Pumpwood.

Example of an app.py:

import os
from dashboard import Dashboard
from pumpwood_communication.microservices import PumpWoodMicroService

###############################################################
# Read env variables to be used on local test of the dashboard.
# Passing a logged microservice to dashboard will disable
# authentication
# !!! DO NOT USE AUTHENTICATED MICROSERVICE IN PRODUCTION
# DASHBOARDS !!! #
MICROSERVICE_URL = os.getenv('MICROSERVICE_URL')
MICROSERVICE_DASHBOARD_USERNAME = os.getenv(
    'MICROSERVICE_DASHBOARD_USERNAME')
MICROSERVICE_DASHBOARD_PASSWORD = os.getenv(
    'MICROSERVICE_DASHBOARD_PASSWORD')

microservice = None
if MICROSERVICE_DASHBOARD_USERNAME is not None:
    microservice = PumpWoodMicroService(
        name="dashboard-microservice",
        server_url=MICROSERVICE_URL,
        username=MICROSERVICE_DASHBOARD_USERNAME,
        password=MICROSERVICE_DASHBOARD_PASSWORD,)
    microservice.login()

dash_obj = Dashboard(microservice=microservice)
dash_obj.run()

Implemented run function:

def run(self) -> None:
    # Set page configuration
    self.set_page_config()

    # Validate auth_header
    is_logged = self.validate_authentication()
    if not is_logged:
        # Authorization error
        self.authentication_error_page()
    else:
        # Render main Dashboard View
        self.main_view()
@abstractmethod
def set_page_config(self) -> None:
154    @abstractmethod
155    def set_page_config(self) -> None:
156        """
157        Set page config, must be implemented.
158
159        Exemple:
160        ```python
161        st.set_page_config(
162            page_title="US Population Dashboard",
163            page_icon="🏂",
164            layout="wide",
165            initial_sidebar_state="expanded")
166        ```
167        """
168        msg = "'set_page_config' function must be implemented"
169        raise NotImplementedError(msg)

Set page config, must be implemented.

Exemple:

st.set_page_config(
    page_title="US Population Dashboard",
    page_icon="🏂",
    layout="wide",
    initial_sidebar_state="expanded")
@abstractmethod
def main_view(self) -> None:
171    @abstractmethod
172    def main_view(self) -> None:
173        """
174        Render main dashboard view.
175
176        Exemple:
177        ```python
178        st.set_page_config(
179            page_title="US Population Dashboard",
180            page_icon="🏂",
181            layout="wide",
182            initial_sidebar_state="expanded")
183        ```
184        """
185        msg = "'main_view' function must be implemented"
186        raise NotImplementedError(msg)

Render main dashboard view.

Exemple:

st.set_page_config(
    page_title="US Population Dashboard",
    page_icon="🏂",
    layout="wide",
    initial_sidebar_state="expanded")