Skip to content

Commit 31e2b1c

Browse files
committed
Added test files
1 parent 0be74fd commit 31e2b1c

11 files changed

Lines changed: 447 additions & 477 deletions

File tree

.dockerignore

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
# Include any files or directories that you don't want to be copied to your
2+
# container here (e.g., local build artifacts, temporary files, etc.).
3+
#
4+
# For more help, visit the .dockerignore file reference guide at
5+
# https://docs.docker.com/go/build-context-dockerignore/
6+
7+
**/.DS_Store
8+
**/__pycache__
9+
**/.venv
10+
**/.classpath
11+
**/.dockerignore
12+
**/.env
13+
**/.git
14+
**/.gitignore
15+
**/.project
16+
**/.settings
17+
**/.toolstarget
18+
**/.vs
19+
**/.vscode
20+
**/*.*proj.user
21+
**/*.dbmdl
22+
**/*.jfm
23+
**/bin
24+
**/charts
25+
**/docker-compose*
26+
**/compose.y*ml
27+
**/Dockerfile*
28+
**/node_modules
29+
**/npm-debug.log
30+
**/obj
31+
**/secrets.dev.yaml
32+
**/values.dev.yaml
33+
LICENSE
34+
README.md
35+
.git
36+
.gitignore
37+
.venv/
38+
__pycache__/
39+
*.log
40+
.python-version
41+
data/
42+
43+
44+
# Python-generated files
45+
__pycache__/
46+
.mypy_cache
47+
.ruff_cache
48+
*.py[cod]
49+
*$py.class
50+
*.so
51+
.Python
52+
build/
53+
develop-eggs/
54+
dist/
55+
downloads/
56+
eggs/
57+
.eggs/
58+
lib/
59+
lib64/
60+
parts/
61+
sdist/
62+
var/
63+
wheels/
64+
*.egg-info/
65+
.installed.cfg
66+
*.egg
67+
68+
# Environment variables
69+
.env
70+
.venv
71+
venv/
72+
env/
73+
ENV/
74+
75+
# IDEs and editors
76+
.idea/
77+
.vscode/
78+
*.swp
79+
*.swo
80+
*~
81+
82+
# Operating System Files
83+
.DS_Store
84+
Thumbs.db
85+
86+
# Jupyter Notebook
87+
.ipynb_checkpoints
88+
89+
# pytest
90+
.pytest_cache/
91+
92+
# Coverage reports
93+
htmlcov/
94+
.coverage
95+
.coverage.*
96+
.cache
97+
98+
# Logs
99+
*.log
100+
101+
# uv specific
102+
.uv/
103+
104+
# DuckDB
105+
*.duckdb
106+
107+
# Scratch Pad
108+
scratch.py

.github/workflows/ci_cd.yml

Lines changed: 21 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,38 +1,32 @@
1-
name: CI/CD
1+
name: CI/CD Pipeline
22

33
on:
44
push:
5-
branches: [ main ]
5+
branches: [dev, main]
66
pull_request:
7-
branches: [ main ]
7+
branches: [main]
88

99
jobs:
10-
test:
10+
ci:
1111
runs-on: ubuntu-latest
1212
steps:
13-
- uses: actions/checkout@v2
14-
- name: Set up Python
15-
uses: actions/setup-python@v2
16-
with:
17-
python-version: '3.11'
18-
- name: Install dependencies
19-
run: |
20-
pip install uv
21-
uv pip install -e .[dev]
22-
- name: Run tests
23-
run: pytest
13+
- uses: actions/checkout@v4
14+
- name: Build dev image
15+
run: make docker-build
16+
- name: Run linting
17+
run: make docker-check
18+
- name: Run tests
19+
run: make docker-test
2420

25-
deploy:
26-
needs: test
27-
runs-on: ubuntu-latest
21+
cd:
22+
needs: ci
2823
if: github.ref == 'refs/heads/main'
24+
runs-on: ubuntu-latest
2925
steps:
30-
- uses: actions/checkout@v2
31-
- name: Build and push Docker image
32-
env:
33-
DOCKER_USERNAME: ${{ secrets.DOCKER_USERNAME }}
34-
DOCKER_PASSWORD: ${{ secrets.DOCKER_PASSWORD }}
35-
run: |
36-
docker build -t your-docker-repo/stock-valuation-app:latest .
37-
echo $DOCKER_PASSWORD | docker login -u $DOCKER_USERNAME --password-stdin
38-
docker push your-docker-repo/stock-valuation-app:latest
26+
- uses: actions/checkout@v4
27+
- name: Build prod image
28+
run: make docker-build-prod
29+
- name: Login to Docker Hub
30+
run: docker login -u ${{ secrets.DOCKER_USERNAME }} -p ${{ secrets.DOCKER_PASSWORD }}
31+
- name: Push prod image
32+
run: make docker-push

.streamlit/config.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
[theme]
22
base="dark"
3-
backgroundColor="#F5F5F5" # "#E3F2FD"
3+
backgroundColor="#F5F5F5"
44
secondaryBackgroundColor="#F0F2F6"
55
textColor="#333333"
66
font="sans serif"

Dockerfile

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,54 @@
1+
# Build stage (with dev tools for linting, testing, etc.)
2+
FROM python:3.11-slim AS builder
3+
WORKDIR /app
4+
5+
# Prevent Python from writing pyc files and buffering output
6+
ENV PYTHONDONTWRITEBYTECODE=1 \
7+
PYTHONUNBUFFERED=1
8+
9+
# Install uv
10+
RUN pip install --no-cache-dir uv
11+
12+
# Copy dependency files first for caching
13+
COPY pyproject.toml uv.lock /app/
14+
15+
# Sync dependencies (includes streamlit, ruff, pytest if in pyproject.toml)
16+
RUN uv sync --frozen
17+
18+
# Copy the rest of the project
19+
COPY . /app
20+
21+
# Final stage (production, lean image)
22+
FROM python:3.11-slim AS production
23+
WORKDIR /app
24+
25+
# Prevent Python from writing pyc files and buffering output
26+
ENV PYTHONDONTWRITEBYTECODE=1 \
27+
PYTHONUNBUFFERED=1
28+
29+
# Create a non-privileged user
30+
ARG UID=10001
31+
RUN adduser \
32+
--disabled-password \
33+
--gecos "" \
34+
--home "/nonexistent" \
35+
--shell "/sbin/nologin" \
36+
--no-create-home \
37+
--uid "${UID}" \
38+
appuser
39+
40+
# Copy the virtual env and project files
41+
COPY --from=builder /app/.venv /app/.venv
42+
COPY . /app
43+
44+
# Set PATH to use the virtual env
45+
ENV PATH="/app/.venv/bin:$PATH"
46+
47+
# Switch to non-privileged user
48+
USER appuser
49+
50+
# Expose Streamlit's default port
51+
EXPOSE 8501
52+
53+
# Run Streamlit app
54+
CMD ["streamlit", "run", "app.py"]

Makefile

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,56 @@
1+
.PHONY: all deps check test docker-build docker-check docker-test docker-build-prod docker-run docker-tag docker-push docker-clean
2+
3+
# Dependency management
4+
deps:
5+
uv sync
6+
7+
# Linting and formatting
8+
check:
9+
- uv run ruff check . --fix
10+
- uv run ruff format .
11+
12+
# Testing
13+
test:
14+
uv run pytest -v
15+
16+
# Dev: Build the dev image (builder stage)
17+
docker-build:
18+
docker build --target builder -t stock-analysis-project:dev .
19+
20+
# Dev: ruff check
21+
docker-check: docker-build
22+
docker run --rm -v $(PWD):/app stock-analysis-project:dev ruff check .
23+
24+
# Dev: test
25+
docker-test: docker-build
26+
docker run --rm stock-analysis-project:dev pytest --verbose
27+
28+
# Prod: Build the production image (production stage)
29+
docker-build-prod:
30+
docker build --target production -t stock-analysis-project:latest .
31+
32+
# Prod: Run the Streamlit app (production image)
33+
docker-run: docker-build-prod
34+
docker run --rm -e API_KEY=${API_KEY} -v $(PWD)/data:/app/data -p 8501:8501 stock-analysis-project:latest
35+
36+
# Prod: Tag production image
37+
docker-tag: docker-build-prod
38+
docker tag stock-analysis-project skytics/stock-analysis-project:latest
39+
40+
# Prod: Push prod image to Docker Hub
41+
docker-push: docker-tag
42+
docker push skytics/stock-analysis-project:latest
43+
44+
# Delete images
45+
docker-clean:
46+
- docker image rm stock-analysis-project:dev || true
47+
- docker image rm stock-analysis-project:latest || true
48+
49+
# All-in-one
50+
all: check test docker-build
51+
@echo "All checks passed!"
52+
53+
54+
55+
56+

pyproject.toml

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,6 @@ requires-python = ">=3.12"
1010

1111
dependencies = [
1212
"asyncio>=3.4.3",
13-
"duckdb>=1.1.3",
1413
"httpx>=0.27.2",
1514
"plotly>=5.24.1",
1615
"polars>=1.12.0",
@@ -20,8 +19,13 @@ dependencies = [
2019

2120
[dependency-groups]
2221
dev = [
23-
"ipykernel>=6.29.5",
24-
"mypy>=1.13.0",
2522
"pytest>=8.3.3",
2623
"ruff>=0.7.3",
27-
]
24+
]
25+
26+
[tool.pytest.ini_options]
27+
pythonpath = ["src"]
28+
testpaths = ["tests"]
29+
python_files = ["test_*.py"]
30+
python_classes = ["Test*"]
31+
python_functions = ["test_*"]

src/app.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -592,10 +592,10 @@ def main():
592592
unsafe_allow_html=True,
593593
)
594594

595-
st.title("Stock Valuation Dashboard")
595+
st.title("Stock Data View")
596596
# st.divider()
597597
st.subheader(
598-
"Get stock quality and valuation insights from historical financial data.",
598+
"Visualize stock fundamentals, ratings, and historical data using the Financial Modeling Prep (FMP) API",
599599
divider="gray",
600600
)
601601

tests/test_data_validation.py

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
from src.data_validation import get_validated_stock_data
2+
3+
4+
def test_get_validated_stock_data_valid_ticker():
5+
"""Test data validation with valid ticker"""
6+
ticker = "AAPL"
7+
data = get_validated_stock_data(ticker)
8+
9+
assert data is not None
10+
assert "profile" in data
11+
assert "quote" in data
12+
assert "ratings" in data
13+
assert "key_metrics_ttm" in data

0 commit comments

Comments
 (0)