Skip to content

Commit

Permalink
Use uv and ruff
Browse files Browse the repository at this point in the history
  • Loading branch information
mkuthan committed Nov 20, 2024
1 parent 0559482 commit 49a74eb
Show file tree
Hide file tree
Showing 16 changed files with 139 additions and 42 deletions.
20 changes: 11 additions & 9 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,19 @@ jobs:
steps:
- uses: actions/checkout@v4

- uses: astral-sh/setup-uv@v3
with:
enable-cache: true

- uses: actions/setup-python@v5
with:
python-version: "3.12"
python-version-file: "pyproject.toml"

- name: Install dependencies
shell: bash
run: |
python -m pip install --upgrade pip
pip install pytest
if [ -f requirements.txt ]; then pip install -r requirements.txt; fi
- name: Update environment
run: uv sync --all-extras --dev

# TODO: add linter(s) (ruff, black, flake8, etc.)
- name: Lint
run: uv run ruff check

- run: pytest
- name: Run tests
run: uv run pytest
24 changes: 24 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ TODO:
* Put tests in separate directory
* Configure Ruff linter
* Verify load balancer strategies (sticky session)
* Dependabot [dependabot#10039](https://github.com/dependabot/dependabot-core/issues/10039)

## Modules

Expand Down Expand Up @@ -70,14 +71,37 @@ TODO:

## Local development

Use VS Code with the following extensions:

* Python
* Ruff

Update environment:

```shell
uv sync
```

Execute the following commands to run the application locally:

```shell
streamlit run app.py
```

Check formatting:

```shell
ruff check
```

Execute tests:

```shell
pytest
```

Show outdated dependencies:

```shell
uv pip list --outdated
```
13 changes: 3 additions & 10 deletions example/service/nyc_tlc_trips.py
Original file line number Diff line number Diff line change
@@ -1,18 +1,11 @@
from datetime import date

import pandas as pd

import streamlit as st

from example.infrastructure import big_query

_PAYMENT_TYPES = {
"1": "Credit card",
"2": "Cash",
"3": "No charge",
"4": "Dispute",
"5": "Unknown",
"6": "Voided trip"
}
_PAYMENT_TYPES = {"1": "Credit card", "2": "Cash", "3": "No charge", "4": "Dispute", "5": "Unknown", "6": "Voided trip"}


@st.cache_data(ttl=600)
Expand All @@ -38,7 +31,7 @@ def get_trips(date_range: tuple[date, date], payment_type: str) -> pd.DataFrame:
params = {
"start_date": date_range[0].isoformat(),
"end_date": date_range[1].isoformat(),
"payment_type": _get_payment_type_key(payment_type)
"payment_type": _get_payment_type_key(payment_type),
}

results = big_query.query(query, params)
Expand Down
1 change: 1 addition & 0 deletions example/ui/components/authentication.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import streamlit as st


def login() -> None:
st.session_state["logged_in"] = True
st.session_state["username"] = "John Doe"
Expand Down
4 changes: 3 additions & 1 deletion example/ui/components/date_range_picker.py
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@
def show(key: str = "date_range_picker") -> tuple[date, date]:
__initialize_state(key)

date_range = st.date_input("Select date range", min_value=_MIN_DATE, max_value=_MAX_DATE, value=st.session_state[key])
value = st.session_state[key]

date_range = st.date_input("Select date range", min_value=_MIN_DATE, max_value=_MAX_DATE, value=value)

if len(date_range) == 2:
st.session_state[key] = date_range
Expand Down
4 changes: 3 additions & 1 deletion example/ui/components/payment_type_selector.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,9 @@
def show(key: str = "payment_type_selector") -> str:
__initialize_state(key)

payment_type = st.selectbox("Payment type", _PAYMENT_TYPE_OPTIONS, index=_PAYMENT_TYPE_OPTIONS.index(st.session_state[key]))
index = _PAYMENT_TYPE_OPTIONS.index(st.session_state[key])

payment_type = st.selectbox("Payment type", _PAYMENT_TYPE_OPTIONS, index=index)
st.session_state[key] = payment_type

return st.session_state[key]
Expand Down
3 changes: 1 addition & 2 deletions example/ui/pages/home.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import streamlit as st

from example.ui.components import date_range_picker
from example.ui.components import payment_type_selector
from example.ui.components import date_range_picker, payment_type_selector

st.title("Home")
st.write("Lorem ipsum dolor sit amet, consectetur adipiscing elit")
Expand Down
3 changes: 1 addition & 2 deletions example/ui/pages/page2.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import streamlit as st

from example.ui.components import date_range_picker
from example.ui.components import payment_type_selector
from example.ui.components import date_range_picker, payment_type_selector

st.title("Page 2")

Expand Down
3 changes: 1 addition & 2 deletions example/ui/pages/page3.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,7 @@
import streamlit as st

from example.service import nyc_tlc_trips
from example.ui.components import date_range_picker
from example.ui.components import payment_type_selector
from example.ui.components import date_range_picker, payment_type_selector

st.title("Page 3")

Expand Down
3 changes: 1 addition & 2 deletions example/ui/pages/page4.py
Original file line number Diff line number Diff line change
@@ -1,7 +1,6 @@
import streamlit as st

from example.ui.components import date_range_picker
from example.ui.components import payment_type_selector
from example.ui.components import date_range_picker, payment_type_selector

st.title("Page 4")

Expand Down
2 changes: 1 addition & 1 deletion example/ui/pages/test_login.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,5 +13,5 @@ def test_login_button_click():

at.button[0].click().run()

assert at.session_state["logged_in"] == True
assert at.session_state["logged_in"] is True
assert at.session_state["username"] == "John Doe"
20 changes: 12 additions & 8 deletions example/ui/pages/test_page3.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@
import pandas.testing as pdt
from streamlit.testing.v1 import AppTest


@patch("example.service.nyc_tlc_trips.get_trips")
def test_show_title(mock_get_trips):
trips = pd.DataFrame()
Expand All @@ -13,16 +14,19 @@ def test_show_title(mock_get_trips):

assert at.title[0].value == "Page 3"


@patch("example.service.nyc_tlc_trips.get_trips")
def test_show_trips(mock_get_trips):
trips = pd.DataFrame({
'day': ['2023-01-01'],
'payment_type': 'Credit card',
'total_fare': [100.0],
'total_tips': [10.0],
'total_amount': [110.0],
'trip_count': [1]
})
trips = pd.DataFrame(
{
"day": ["2023-01-01"],
"payment_type": "Credit card",
"total_fare": [100.0],
"total_tips": [10.0],
"total_amount": [110.0],
"trip_count": [1],
}
)
mock_get_trips.return_value = trips

at = AppTest.from_file("page3.py").run()
Expand Down
38 changes: 38 additions & 0 deletions pyproject.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
[project]
name = "example-streamlit"
description = "Non-trivial Streamlit application skeleton implemented in a 'Streamlit way'"
version = "1.0.0"
requires-python = "~=3.12"

dependencies = [
"streamlit==1.39.0",
# bigquery integration
"google-cloud-bigquery==3.25.0",
"db-dtypes==1.3.1",
]

[tool.uv]
dev-dependencies = [
"pytest==8.3.3",
# linter and formatter
"ruff==0.7.4",
# speedup source code monitoring and live reloading
"watchdog==2.1.6",
]

[tool.pytest.ini_options]
pythonpath = "."

[tool.ruff]
line-length = 120

[tool.ruff.lint]
select = [
"E", # pycodestyle errors
"W", # pycodestyle warnings
"F", # pyflakes
"I", # isort
"B", # flake8-bugbear
"C4", # flake8-comprehensions
"UP", # pyupgrade
]
2 changes: 0 additions & 2 deletions pytest.ini

This file was deleted.

4 changes: 3 additions & 1 deletion test_app.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def test_show_app_authenticated():
assert at.button[0].label == "Share"
assert at.button[1].label == "Log out"


def test_logout_button_click():
at = AppTest.from_file("app.py")
at.session_state["logged_in"] = True
Expand All @@ -27,7 +28,7 @@ def test_logout_button_click():

at.button[1].click().run()

assert at.session_state["logged_in"] == False
assert at.session_state["logged_in"] is False
assert at.session_state["username"] is None


Expand All @@ -39,6 +40,7 @@ def test_decode_valid_state():
assert at.session_state["k1"] == "v1"
assert at.session_state["k2"] == "v2"


def test_decode_and_merge_valid_state():
at = AppTest.from_file("app.py")
at.session_state["k1"] = "v1"
Expand Down
37 changes: 36 additions & 1 deletion uv.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit 49a74eb

Please sign in to comment.