From 275d82956da466d4c2306ff2767dda71fd18edc5 Mon Sep 17 00:00:00 2001 From: Mira Date: Mon, 25 Mar 2024 10:56:30 +0100 Subject: [PATCH] add mypy static type checking for frontend to pre-commit --- .pre-commit-config.yaml | 12 +++++++++++- frontend/mypy.ini | 10 ++++++++++ frontend/streamlit_app.py | 36 +++++++++++++++++++----------------- frontend/utils/__init__.py | 0 frontend/utils/helpers.py | 22 +++++++++++++++++++--- 5 files changed, 59 insertions(+), 21 deletions(-) create mode 100644 frontend/mypy.ini create mode 100644 frontend/utils/__init__.py diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index 06890bb..7108725 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -11,4 +11,14 @@ repos: - repo: https://github.com/astral-sh/ruff-pre-commit rev: v0.3.4 hooks: - - id: ruff \ No newline at end of file + - id: ruff + +# mypy static type checker +- repo: https://github.com/pre-commit/mirrors-mypy + rev: v1.8.0 + hooks: + - id: mypy + name: mypy-frontend + files: ^frontend/ + args: [--config-file=frontend/mypy.ini] + additional_dependencies: [types-requests] diff --git a/frontend/mypy.ini b/frontend/mypy.ini new file mode 100644 index 0000000..c1ed88c --- /dev/null +++ b/frontend/mypy.ini @@ -0,0 +1,10 @@ +[mypy] +# https://mypy.readthedocs.io/en/stable/config_file.html + +python_version = 3.10 +disallow_incomplete_defs = True +no_implicit_optional = True +install_types = True +exclude = frontend/utils/request_wrapper.py +ignore_missing_imports = True + diff --git a/frontend/streamlit_app.py b/frontend/streamlit_app.py index 7a4fbc0..20daff0 100644 --- a/frontend/streamlit_app.py +++ b/frontend/streamlit_app.py @@ -1,17 +1,22 @@ # run command from root: streamlit run streamlit_app.py +import os +import sys +import logging import pathlib import random -from fastapi import UploadFile +from typing import Callable + +from streamlit.runtime.uploaded_file_manager import UploadedFile + +# from fastapi import UploadFile import streamlit as st from streamlit_option_menu import option_menu from streamlit_extras.add_vertical_space import add_vertical_space from streamlit_extras.stylable_container import stylable_container import requests -import os -import sys -import logging -import certifi + from PIL import Image +import certifi from dotenv import load_dotenv import sentry_sdk @@ -35,7 +40,7 @@ logging.info(f"{API_URL=}") APP_TITLE = "Quaigle" -MAIN_PAGE = {} +PAGE_REGISTRY_DICT: dict[str, Callable[..., None]] = {} cfd = pathlib.Path(__file__).parent logging.basicConfig(stream=sys.stdout, level=logging.INFO) @@ -169,21 +174,18 @@ def display_options_menu(): st.session_state["redirect_page"] = None -def make_get_request(route: str): +def make_get_request(route: str) -> requests.Response: return requests.get(os.path.join(API_URL, route)) def post_data_to_backend( - route: str, url: str = "", uploaded_file: UploadFile | None = None -): + route: str, url: str = "", uploaded_file: UploadedFile | None = None +) -> None: with st.spinner("Waiting for openai API response"): try: if url: data = {"upload_url": url} - files = {"upload_file": ("", None)} - response = requests.post( - os.path.join(API_URL, route), data=data, files=files - ) + response = requests.post(os.path.join(API_URL, route), data=data) elif uploaded_file: files = {"upload_file": (uploaded_file.name, uploaded_file)} data = {"upload_url": ""} @@ -287,7 +289,7 @@ def display_sidemenu(): st.experimental_rerun() -@register_page(MAIN_PAGE) +@register_page(PAGE_REGISTRY_DICT) def questionai(): with st.container(): for message in st.session_state.messages: @@ -335,7 +337,7 @@ def questionai(): ) -@register_page(MAIN_PAGE) +@register_page(PAGE_REGISTRY_DICT) def quizme(): with st.container(): if st.session_state["chat_mode"] == "database": @@ -392,7 +394,7 @@ def quizme(): ) -@register_page(MAIN_PAGE) +@register_page(PAGE_REGISTRY_DICT) def statistics(): import pandas as pd @@ -436,7 +438,7 @@ def main(): display_header() display_sidemenu() # implement the selected page from options menu - MAIN_PAGE[st.session_state.selected_page]() + PAGE_REGISTRY_DICT[st.session_state.selected_page]() if __name__ == "__main__": diff --git a/frontend/utils/__init__.py b/frontend/utils/__init__.py new file mode 100644 index 0000000..e69de29 diff --git a/frontend/utils/helpers.py b/frontend/utils/helpers.py index 5e0d95e..e00fafe 100644 --- a/frontend/utils/helpers.py +++ b/frontend/utils/helpers.py @@ -1,7 +1,23 @@ -def register_page(page_dict: dict[str, callable]) -> callable: - """decorator to register page automatically in page dict""" +from typing import Callable, TypeVar + +F = TypeVar("F", bound=Callable[..., None]) + + +def register_page(page_registry_dict: dict[str, F]) -> Callable[[F], F]: + """ + Streamlit page decorator (factory) which takes the page registry dict + as argument and returns the actual decorator, which itself registers + all decorated page functions automatically in page dict. + + Args: + page_registry_dict: the dict where to register the page + + Returns: + Callable: the actual decorator, a callable which takes a callable as + argument and returns it. + """ def inner(func): - page_dict[func.__name__] = func + page_registry_dict[func.__name__] = func return inner