Skip to content

Commit fdc7798

Browse files
authored
Add initial StockDataView app with Streamlit and Docker (#1)
* Added codes to python files * Modified python code files * Cleaned up files * Updated fmp_client.py file * Started work on valuation.py file * Modified Stock.py file. * Modified project structure * Modified code files * Streamlined the project structure * Added data_validation module * Changed line to bar charts * Added test files * Modified app.py file * Modified toml file. * Updated ci_cd.yml file * Modified ci_cd.yml, Makefile and README.md files * Removed hanging spaces in makefile * Updated README and Makefile * Refactored the app code
1 parent 75eb2c2 commit fdc7798

30 files changed

Lines changed: 1862 additions & 705 deletions

.dockerignore

Lines changed: 90 additions & 43 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,108 @@
1-
# Git
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
235
.git
336
.gitignore
4-
5-
# Python
6-
__pycache__
7-
*.pyc
8-
*.pyo
9-
*.pyd
10-
.Python
11-
env
12-
venv
13-
pip-log.txt
14-
pip-delete-this-directory.txt
15-
.tox
16-
.coverage
17-
.coverage.*
18-
.cache
19-
nosetests.xml
20-
coverage.xml
21-
*.cover
37+
.venv/
38+
__pycache__/
2239
*.log
40+
.python-version
41+
data/
42+
43+
44+
# Python-generated files
45+
__pycache__/
2346
.mypy_cache
24-
.pytest_cache
25-
.hypothesis
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
2667

27-
# Environments
68+
# Environment variables
2869
.env
2970
.venv
30-
env/
3171
venv/
72+
env/
3273
ENV/
3374

34-
# IDEs
35-
.vscode
36-
.idea
75+
# IDEs and editors
76+
.idea/
77+
.vscode/
78+
*.swp
79+
*.swo
80+
*~
3781

38-
# OS generated files
82+
# Operating System Files
3983
.DS_Store
40-
.DS_Store?
41-
._*
42-
.Spotlight-V100
43-
.Trashes
44-
ehthumbs.db
4584
Thumbs.db
4685

47-
# Project specific
48-
tests/
49-
*.md
50-
LICENSE
51-
.github/
52-
docker-compose.yml
53-
54-
# DuckDB
55-
*.duckdb
56-
5786
# Jupyter Notebook
5887
.ipynb_checkpoints
5988

89+
# pytest
90+
.pytest_cache/
91+
92+
# Coverage reports
93+
htmlcov/
94+
.coverage
95+
.coverage.*
96+
.cache
97+
98+
# Logs
99+
*.log
100+
60101
# uv specific
61-
.uv/
102+
.uv/
103+
104+
# DuckDB
105+
*.duckdb
106+
107+
# Scratch Pad
108+
scratch.py

.github/workflows/ci_cd.yml

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
name: CI/CD Pipeline
2+
3+
on:
4+
pull_request:
5+
branches:
6+
- main
7+
8+
jobs:
9+
ci:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v4
13+
14+
- name: Build and Check (using multi-stage Dockerfile)
15+
run: make docker-check-ci
16+
17+
cd:
18+
needs: ci
19+
if: github.ref == 'refs/heads/main'
20+
runs-on: ubuntu-latest
21+
steps:
22+
- uses: actions/checkout@v4
23+
24+
- name: Build prod image
25+
run: make docker-build-prod
26+
27+
- name: Login to Docker Hub
28+
uses: docker/login-action@v3
29+
with:
30+
username: ${{ secrets.DOCKERHUB_USERNAME }}
31+
password: ${{ secrets.DOCKERHUB_TOKEN }}
32+
33+
- name: Push prod image
34+
run: make docker-push

.gitignore

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
11
# Python-generated files
22
__pycache__/
3+
.mypy_cache
4+
.ruff_cache
35
*.py[cod]
46
*$py.class
57
*.so
@@ -57,4 +59,7 @@ htmlcov/
5759
.uv/
5860

5961
# DuckDB
60-
*.duckdb
62+
*.duckdb
63+
64+
# Scratch Pad
65+
scratch.py

.streamlit/config.toml

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
[theme]
2+
base="dark"
3+
backgroundColor="#F5F5F5"
4+
secondaryBackgroundColor="#F0F2F6"
5+
textColor="#333333"
6+
font="sans serif"

Dockerfile

Lines changed: 67 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,67 @@
1+
# ------------------------------- Builder Satge -------------------------------
2+
3+
# Build stage (with dev tools for linting, testing, etc.)
4+
FROM python:3.13-slim-bookworm AS builder
5+
6+
# The installer requires curl (and certificates) to download the release archive
7+
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates && \
8+
apt-get clean && rm -rf /var/lib/apt/lists/*
9+
10+
# Download the latest installer, install it, and remove it
11+
ADD https://astral.sh/uv/install.sh /uv-installer.sh
12+
RUN chmod -R 655 /uv-installer.sh && /uv-installer.sh && rm /uv-installer.sh
13+
14+
# Set up uv environment PATH
15+
ENV PATH="/root/.local/bin/:$PATH"
16+
17+
WORKDIR /app
18+
19+
# Prevent Python from writing pyc files and buffering output
20+
ENV PYTHONDONTWRITEBYTECODE=1 \
21+
PYTHONUNBUFFERED=1
22+
23+
# Copy dependency files first for caching
24+
COPY pyproject.toml /app/
25+
26+
# Sync dependencies (includes streamlit, ruff, pytest if in pyproject.toml)
27+
RUN uv sync
28+
29+
# Copy the rest of the project
30+
COPY . /app
31+
32+
# ------------------------- Production Stage -------------------------
33+
34+
# Final stage (production, lean image)
35+
FROM python:3.13-slim-bookworm AS production
36+
WORKDIR /app
37+
38+
# Prevent Python from writing pyc files and buffering output
39+
ENV PYTHONDONTWRITEBYTECODE=1 \
40+
PYTHONUNBUFFERED=1
41+
42+
# Create a non-privileged user
43+
ARG UID=10001
44+
RUN adduser \
45+
--disabled-password \
46+
--gecos "" \
47+
--home "/nonexistent" \
48+
--shell "/sbin/nologin" \
49+
--no-create-home \
50+
--uid "${UID}" \
51+
appuser
52+
53+
# Copy the virtual env and project files
54+
COPY --from=builder /app/.venv /app/.venv
55+
COPY . /app
56+
57+
# Set PATH to use the virtual env
58+
ENV PATH="/app/.venv/bin:$PATH"
59+
60+
# Switch to non-privileged user
61+
USER appuser
62+
63+
# Expose Streamlit's default port
64+
EXPOSE 8501
65+
66+
# Run Streamlit app
67+
CMD ["streamlit", "run", "src/app.py"]

Makefile

Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
.PHONY: all deps check test docker-build-dev docker-check docker-test docker-check-ci docker-build-prod docker-run 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 builder stage image
17+
docker-build-dev:
18+
docker build --target builder -t stockdataview:dev .
19+
20+
# Dev: Run linting in container
21+
docker-check: docker-build-dev
22+
docker run --rm -v $(PWD):/app stockdataview:dev uv run ruff check .
23+
24+
# Dev: Run tests in container
25+
docker-test: docker-build-dev
26+
docker run --rm stockdataview:dev uv run pytest -v
27+
28+
# CI specific target: Build up to the builder stage and run checks/tests
29+
docker-check-ci: docker-build-dev
30+
- docker run --rm -v $(PWD):/app stockdataview:dev uv run ruff check .
31+
- docker run --rm -v $(PWD):/app stockdataview:dev uv run pytest -v
32+
33+
34+
# Prod: Build the production stage image
35+
docker-build-prod:
36+
docker build --target production -t skytics/stockdataview:latest .
37+
38+
# Prod: Run the app locally
39+
docker-run: docker-build-prod
40+
docker run --rm -e FMP_API_KEY=${FMP_API_KEY} -p 8501:8501 skytics/stockdataview:latest
41+
42+
# Prod: Push to Docker Hub
43+
docker-push: docker-build-prod
44+
docker push skytics/stockdataview:latest
45+
46+
# Clean up images
47+
docker-clean:
48+
- docker image rm stockdataview:dev || true
49+
- docker image rm skytics/stockdataview:latest || true
50+
51+
# All-in-one for local dev
52+
all: check test docker-build-dev
53+
@echo "All checks passed!"

0 commit comments

Comments
 (0)