Design — pinky-streamlit
Update date : 2026-05-31
Architecture decisions, constraints, and trade-offs for pinky-streamlit.
Placement in the suite
pinky-streamlit belongs in this kit because it requires streamlit as a runtime dependency.
The rule: any module that imports streamlit at the top level goes here — not in pinky-core.
This keeps pinky-core importable in CI, UDFs, and local scripts without pulling in the Streamlit
runtime.
CSS architecture — module-scoped
style.css at the package root does Streamlit normalization only (reset, font injection, spacing).
Each ui_components/<module>/ owns its own .css file loaded on demand by setup_page().
Why: a page that uses only metric and header should not load chart CSS or table CSS.
Loading on demand keeps SiS startup time predictable as the kit grows.
Version pin
streamlit==1.52.2 and plotly==5.24.1 are hard-pinned. The CSS design system
uses internal Streamlit CSS selectors that change between versions.
Upgrading requires a full visual validation pass before the pin moves.
See docs/reference/generated/api/ for the validated upgrade workflow.
Import alias convention
Module functions are imported with sks_ prefix to avoid shadowing st.* names:
from pinky_streamlit import text as sks_text, metric as sks_metric
Why: Streamlit apps are full of st. calls. An alias makes it immediately clear
which components come from the kit vs the Streamlit stdlib.
Local dev mode
get_session() resolves transparently:
- SiS: returns the active Snowpark session
- Local (PINKY_LOCAL=1): returns a LocalSessionConfig backed by DuckDB
App code never changes — only the resolution layer switches.
Local data is populated by pinky dump (from snowflake-tools).
What is deliberately out of scope
- Pure Python utilities (formatters, validators) →
pinky-core - Snowpark session management beyond
get_session()→pinky-snowpark - External API calls →
pinky-connect - Any component that doesn't require
streamlitat import time
Container Runtime vs legacy SiS
Two deployment contexts are supported. App code does not change between them —
only setup_page() arguments and the presence of config.toml differ.
| Legacy SiS (warehouse) | Container Runtime (Workspace) | |
|---|---|---|
config.toml |
Not supported | Full support |
| Custom font | Base64 data URI (font=DEFAULT_FONT) |
fontFiles in config.toml (font=None) |
primaryColor |
CSS override (KNOWN LIMITATIONS) | Native via config.toml (slider + date picker fixed) |
| CSS variables | setup_page() CSS injection |
Same — config.toml does not replace CSS variables |
| External packages | Anaconda channel only | Any pip package (with EAI) |
Container Runtime setup
# 1. Generate .streamlit/config.toml once — commit to project
from pinky_streamlit import PALETTES
print(PALETTES.PYTHIA.to_config_toml(font_files=["static/DMSans.woff2"]))
# 2. Each page
setup_page(session, palette=PALETTES.PYTHIA, font=None)
setup_page() still injects style.css + CSS variables in both modes.
config.toml handles what CSS cannot: primaryColor at React level and font loading.
See ADR-0006 for the full rationale.