Metadata-Version: 2.4
Name: streamtree
Version: 0.1.0
Summary: Composable, typed Streamlit applications with a declarative component model.
Author: Streamtree contributors
License-Expression: MIT
Project-URL: Homepage, https://github.com/streamtree-dev/streamtree
Project-URL: Documentation, https://github.com/streamtree-dev/streamtree#readme
Project-URL: Repository, https://github.com/streamtree-dev/streamtree
Project-URL: Issues, https://github.com/streamtree-dev/streamtree/issues
Project-URL: Changelog, https://github.com/streamtree-dev/streamtree/blob/main/CHANGELOG.md
Keywords: streamlit,ui,components,declarative
Classifier: Development Status :: 3 - Alpha
Classifier: Intended Audience :: Developers
Classifier: Programming Language :: Python :: 3
Classifier: Programming Language :: Python :: 3.10
Classifier: Programming Language :: Python :: 3.11
Classifier: Programming Language :: Python :: 3.12
Classifier: Typing :: Typed
Requires-Python: >=3.10
Description-Content-Type: text/markdown
License-File: LICENSE
Requires-Dist: streamlit>=1.28.0
Provides-Extra: dev
Requires-Dist: pytest>=7.4.0; extra == "dev"
Requires-Dist: pytest-cov>=4.1.0; extra == "dev"
Requires-Dist: pytest-xdist>=3.5.0; extra == "dev"
Requires-Dist: mypy>=1.8.0; extra == "dev"
Requires-Dist: ruff>=0.2.0; extra == "dev"
Requires-Dist: ty>=0.0.30; extra == "dev"
Dynamic: license-file

# Streamtree

**Composable, typed Streamlit applications** — a small Python layer that turns UIs into declarative trees instead of long imperative scripts.

Streamtree keeps Streamlit’s execution model and widgets, but adds **components**, **virtual elements**, **scoped session state**, and a path toward **Pydantic-typed** forms and props. No JavaScript is required for the core experience.

---

## Why Streamtree

| Without Streamtree | With Streamtree |
|--------------------|-----------------|
| Layout and widgets interleaved in one script | `@component` functions return a **tree** of elements |
| `st.session_state` keys scattered and stringly | `state()` keys scoped to the render path |
| Hard to snapshot or reason about structure | `streamtree.testing.render_to_tree()` for structure checks |

Streamtree is **not** a React clone, a browser framework, or a JS build step. It is an **architecture layer** for teams who want maintainable Streamlit apps.

---

## Features

- **Python-first** — decorators, plain functions, standard typing
- **Declarative layouts** — `Page`, `Card`, `Grid`, `VStack`, `Form`, `Tabs`, `Sidebar`, …
- **Session-backed state** — `state`, `toggle_state`, `form_state`, `memo`, `cache`
- **Streamlit renderer** — virtual tree → `st.*` on each rerun
- **Testing helpers** — serialize trees for snapshots (`render_to_tree`)
- **Typed trajectory** — roadmap and dependency strategy center on **Pydantic** and curated optional extras

---

## Requirements

- **Python 3.10+**
- **Streamlit ≥ 1.28** (declared in `pyproject.toml`)

---

## Install

**From PyPI** (after you publish this version):

```bash
pip install streamtree==0.1.0
```

**From a clone** (editable, with dev tools):

```bash
git clone https://github.com/streamtree-dev/streamtree.git
cd streamtree
pip install -e ".[dev]"
# or, with uv:
uv sync --extra dev
```

Optional install groups (`tables`, `charts`, `ui`, `auth`, `all`) are specified in the [dependency strategy](docs/STREAMTREE_DEPENDENCY_STRATEGY.md) and will appear in `pyproject.toml` as those integrations ship.

---

## Quick start

```python
from streamtree import component, render
from streamtree.elements import Button, Card, Page, Text
from streamtree.state import state


@component
def Counter():
    count = state(0)

    return Card(
        Text(f"Count: {count()}"),
        Button("Increment", on_click=lambda: count.increment(1)),
        Button("Reset", on_click=lambda: count.set(0)),
    )


if __name__ == "__main__":
    render(Page(Counter()))
```

Run the bundled demo from the repo root:

```bash
streamlit run examples/counter.py
```

---

## Layout and state at a glance

**Grid of components**

```python
from streamtree.elements import Grid

Grid(
    UserCard(user1),
    UserCard(user2),
    columns=2,
)
```

**Bound text input**

```python
from streamtree.elements import TextInput
from streamtree.state import state

search = state("")
TextInput(label="Search", value=search)
```

---

## Project layout

```text
src/streamtree/     # installable package
  core/             # elements, @component, render, context
  elements/         # layouts + widgets
  state/            # session state helpers
  renderers/        # Streamlit backend
  testing/          # tree serialization for tests
docs/               # plan, roadmap, dependency strategy
examples/           # runnable Streamlit examples
tests/              # pytest
```

---

## Documentation

| Document | Contents |
|----------|----------|
| [STREAMTREE_PLAN.md](docs/STREAMTREE_PLAN.md) | Vision, goals, architecture, risks |
| [STREAMTREE_ROADMAP.md](docs/STREAMTREE_ROADMAP.md) | Phased delivery and dependency alignment |
| [STREAMTREE_DEPENDENCY_STRATEGY.md](docs/STREAMTREE_DEPENDENCY_STRATEGY.md) | Base vs optional deps, extras, wrapper-first API |
| [CHANGELOG.md](CHANGELOG.md) | Version history |

---

## Contributing

With **[uv](https://docs.astral.sh/uv/)** (recommended):

```bash
uv sync --extra dev
uv run ruff check src tests
uv run ty check src
uv run pytest
```

With **pip**:

```bash
pip install -e ".[dev]"
ruff check src tests
ty check src
pytest
```

CI runs the same checks on Python 3.10–3.12 (see `.github/workflows/ci.yml`).

### Publishing

For **0.1.0**, build artifacts with `uv build` (or `python -m build`), then upload the contents of `dist/` to PyPI using **twine**, **uv publish**, or [Trusted Publishing](https://docs.pypi.org/trusted-publishers/). Tag the release commit `v0.1.0` on your default branch and record changes in [CHANGELOG.md](CHANGELOG.md). Keep `version` in `pyproject.toml`, `streamtree.__version__`, `tests/test_package_meta.py`, and the changelog entry aligned when you cut releases.

---

## License

MIT — see the [`LICENSE`](LICENSE) file.
