Skip to content

Migrate to pydantic v2; drop unmaintained streamlit_pydantic#10

Merged
thorwhalen merged 1 commit into
masterfrom
pydantic-v2-migration
May 20, 2026
Merged

Migrate to pydantic v2; drop unmaintained streamlit_pydantic#10
thorwhalen merged 1 commit into
masterfrom
pydantic-v2-migration

Conversation

@thorwhalen
Copy link
Copy Markdown
Member

Closes #9.

Why

front has moved to pydantic v2 (i2mint/front#30, merged). streamlitfront consumes front.py2pydantic and was the next package keeping the ecosystem (extrude, anything composing front elements) pinned to pydantic v1.

The blocker: streamlit_pydantic

streamlit_pydantic's last release — 0.6.0 (2022) — imports pydantic.BaseSettings, removed in pydantic v2. There is no v2-compatible release on PyPI; the package is effectively abandoned.

Rather than pin the whole ecosystem to pydantic v1 for the sake of one
unmaintained dependency, the small subset of streamlit_pydantic that
streamlitfront actually used is reimplemented natively against pydantic v2
and streamlit's own widgets.

What changed

streamlitfront/pydantic_widgets.py (new, ~115 lines)

A drop-in replacement for import streamlit_pydantic as sp:

function behaviour
pydantic_input(key, model) one widget per field, returns a validated model instance (or None on validation error)
pydantic_form(key, model) same, wrapped in st.form + submit button; returns the instance on submit, else None
pydantic_output(instance) renders the instance as JSON

Widget type is chosen per field from model.model_fields (bool → checkbox,
int/float → number_input, everything else → text_input; Optional[X] is
unwrapped to X).

streamlitfront/page_funcs.py

SimplePageFuncPydanticWrite / SimplePageFuncPydanticWithOutput now use
streamlitfront.pydantic_widgets. Result handling uses
instance.model_dump() rather than dict(instance).

streamlitfront/tests/test_pydantic_widgets.py (new)

  • Unit tests for the pure helper (_unwrap_optional).
  • Integration tests via streamlit.testing.v1.AppTest: render the
    widgets in a headless Streamlit run, edit them, and confirm a validated
    model instance is produced; confirm pydantic_form returns None until
    submitted.

streamlitfront/tests/dummy_app.py

Same import swap; added the missing module docstring.

setup.cfg

  • Drop streamlit_pydantic.
  • Add pydantic>=2 explicitly (it was imported at module-load time but
    never declared).

Migration guide for downstream code

If you imported streamlit_pydantic via streamlitfront, switch to
from streamlitfront import pydantic_widgets as sp — the three functions
above keep the same names. Note pydantic_input / pydantic_form now
return a pydantic model instance (not a dict); use .model_dump() if
you need a plain dict.

General pydantic v1→v2 changes (see front#30) also apply:

v1 v2
model.__fields__ model.model_fields
instance.dict() instance.model_dump()
model.schema_json() json.dumps(model.model_json_schema())

Verified

$ python -m pytest streamlitfront/tests/test_base.py \
    streamlitfront/tests/test_pydantic_widgets.py
======================== 5 passed, 3 warnings in 0.17s ========================

All imports resolve with no streamlit_pydantic installed, under
pydantic 2.12.

Follow-up

extrude can now drop its temporary CI workarounds (Python 3.12 + Windows
skip) once a new streamlitfront is on PyPI.

front has moved to pydantic v2 (i2mint/front#30). streamlitfront
consumes front.py2pydantic and was the next package pinning the
ecosystem to pydantic v1.

The blocker was the streamlit_pydantic dependency: its last release
(0.6.0, 2022) imports pydantic.BaseSettings, which was removed in
pydantic v2, and there is no v2-compatible release. Rather than keep
the ecosystem on pydantic v1, the small subset of streamlit_pydantic
that streamlitfront used is reimplemented natively.

Changes
-------
- streamlitfront/pydantic_widgets.py (new)
  Native-Streamlit rendering of pydantic v2 models — a drop-in for the
  old `import streamlit_pydantic as sp`:
    * pydantic_input(key, model)  -> validated instance (or None)
    * pydantic_form(key, model)   -> instance on submit, else None
    * pydantic_output(instance)   -> render as JSON
  Widgets are chosen per field type via model.model_fields.

- streamlitfront/page_funcs.py
  SimplePageFuncPydanticWrite / SimplePageFuncPydanticWithOutput now
  use streamlitfront.pydantic_widgets. Result handling uses
  instance.model_dump() instead of dict(instance).

- streamlitfront/tests/dummy_app.py
  Same import swap; added the missing module docstring.

- streamlitfront/tests/test_pydantic_widgets.py (new)
  Covers the new module: pure-helper unit tests plus AppTest-based
  integration tests that render the widgets in a headless Streamlit
  run and confirm a validated model instance is built.

- setup.cfg
  Drop streamlit_pydantic; add an explicit pydantic>=2 requirement
  (it was used at import time but never declared).
@thorwhalen thorwhalen merged commit 1afef86 into master May 20, 2026
4 checks passed
@thorwhalen thorwhalen deleted the pydantic-v2-migration branch May 20, 2026 09:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Bump dependencies to pydantic v2 (after front #30)

1 participant