diff --git a/.github/workflows/python-app.yml b/.github/workflows/python-app.yml new file mode 100644 index 000000000..a746ede12 --- /dev/null +++ b/.github/workflows/python-app.yml @@ -0,0 +1,39 @@ +# This workflow will install Python dependencies, run tests and lint with a single version of Python +# For more information see: https://docs.github.com/en/actions/automating-builds-and-tests/building-and-testing-python + +name: Python application + +on: + push: + branches: [ "main" ] + pull_request: + branches: [ "main" ] + +permissions: + contents: read + +jobs: + build: + + runs-on: ubuntu-latest + + steps: + - uses: actions/checkout@v3 + - name: Set up Python 3.10 + uses: actions/setup-python@v3 + with: + python-version: "3.10" + - name: Install dependencies + run: | + python -m pip install --upgrade pip + pip install flake8 pytest + if [ -f requirements.txt ]; then pip install -r requirements.txt; fi + - name: Lint with flake8 + run: | + # stop the build if there are Python syntax errors or undefined names + flake8 . --count --select=E9,F63,F7,F82 --show-source --statistics + # exit-zero treats all errors as warnings. The GitHub editor is 127 chars wide + flake8 . --count --exit-zero --max-complexity=10 --max-line-length=127 --statistics + - name: Test with pytest + run: | + pytest -vv diff --git a/.gitignore b/.gitignore index c9863bac6..083db109c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,4 @@ .venv -secrets.toml __pycache__/ +.DS_Store +secrets.toml diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index d8afdf641..25c8db679 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -10,4 +10,4 @@ repos: hooks: - id: black language_version: python3.11 - args: ["--line-length", "100"] + args: ["--line-length", "105"] diff --git a/app_test.py b/app_test.py new file mode 100644 index 000000000..75cf76570 --- /dev/null +++ b/app_test.py @@ -0,0 +1,46 @@ +from unittest.mock import patch +from streamlit.testing.v1 import AppTest +from openai.openai_object import OpenAIObject + + +# See https://github.com/openai/openai-python/issues/398 +def create_openai_object_sync(response: str, role: str = "assistant") -> OpenAIObject: + obj = OpenAIObject() + message = OpenAIObject() + content = OpenAIObject() + content.content = response + content.role = role + message.message = content + obj.choices = [message] + return obj + + +@patch("openai.ChatCompletion.create") +def test_Chatbot(openai_create): + at = AppTest.from_file("Chatbot.py").run() + assert not at.exception + at.chat_input[0].set_value("Do you know any jokes?").run() + assert at.info[0].value == "Please add your OpenAI API key to continue." + + JOKE = "Why did the chicken cross the road? To get to the other side." + openai_create.return_value = create_openai_object_sync(JOKE) + at.text_input(key="chatbot_api_key").set_value("sk-...") + at.chat_input[0].set_value("Do you know any jokes?").run() + print(at) + assert at.chat_message[1].markdown[0].value == "Do you know any jokes?" + assert at.chat_message[2].markdown[0].value == JOKE + assert at.chat_message[2].avatar == "assistant" + assert not at.exception + + +@patch("langchain.llms.OpenAI.__call__") +def test_Langchain_Quickstart(langchain_llm): + at = AppTest.from_file("pages/3_Langchain_Quickstart.py").run() + assert at.info[0].value == "Please add your OpenAI API key to continue." + + RESPONSE = "1. The best way to learn how to code is by practicing..." + langchain_llm.return_value = RESPONSE + at.sidebar.text_input[0].set_value("sk-...") + at.button[0].set_value(True).run() + print(at) + assert at.info[0].value == RESPONSE diff --git a/requirements-dev.txt b/requirements-dev.txt index 872abf3b2..8635be6db 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -2,3 +2,4 @@ black==23.3.0 mypy==1.4.1 pre-commit==3.3.3 watchdog +pytest diff --git a/requirements.txt b/requirements.txt index c2737f628..9b90305d8 100644 --- a/requirements.txt +++ b/requirements.txt @@ -1,4 +1,4 @@ -streamlit>=1.26.0 +streamlit>=1.28 langchain>=0.0.217 openai duckduckgo-search