Skip to content

fix(specs): unwrap ju rjsf form spec + modernize packaging metadata - #3

Merged
thorwhalen merged 2 commits into
masterfrom
wads/fix-rjsf-spec-and-metadata
Jul 30, 2026
Merged

fix(specs): unwrap ju rjsf form spec + modernize packaging metadata#3
thorwhalen merged 2 commits into
masterfrom
wads/fix-rjsf-spec-and-metadata

Conversation

@thorwhalen

Copy link
Copy Markdown
Member

The bug

uf/specs.py called func_to_form_spec(func, **self._rjsf_config). But
ju.rjsf.func_to_form_spec defaults to nest_under_field="rjsf", so it returns:

{"rjsf": {"schema": {...}, "uiSchema": {...}}}

_generate_spec then read form_spec.get("schema", {}) — which always yielded
{}. Every generated RJSF form was empty whenever ju imported
successfully.
This is user-facing, not a test artifact: uf/routes.py serves
spec["schema"] straight to the browser in two places.

This was masked in CI because the broad except ImportError: around the ju
call block silently falls back to _generate_basic_spec, which happens to emit
the flat shape — so CI was green while the ju integration (the package's whole
point) was never actually exercised.

The fix

Pass nest_under_field=None, via a dict merge so caller overrides in
_rjsf_config still win:

rjsf_config = {"nest_under_field": None, **self._rjsf_config}
form_spec = func_to_form_spec(func, **rjsf_config)

Safe in both environments: it makes the ju path emit exactly the same flat
shape the ImportError fallback already emits. The except ImportError: clause
is deliberately left untouched in this PR (see Deliberately out of scope).

Test counts

before after
python -m pytest -q 2 failed / 27 passed 29 passed
dependents gate (test-dependents uf) 0 pass / 1 fail 1 pass / 0 fail

Previously failing: tests/test_specs.py::test_function_spec_schema_basic
(KeyError: 'type') and tests/test_specs.py::test_function_spec_required_params
(assert 'name' in []).

Packaging metadata

  • license: deprecated [project.license] text = "mit" table -> PEP 639 SPDX
    string license = "MIT" (canonical case). No License :: OSI Approved ::
    trove classifier added — PyPI rejects that combination alongside an SPDX
    expression.
  • keywords / authors: were empty placeholders ([]), now filled in.
  • classifiers: were absent entirely, so the PyPI page carried no trove
    metadata. Eight added.
  • description: "UI Fast" -> the README tagline
    "Minimal-boilerplate web UIs for Python functions". The GitHub repo
    description is set to the same string so the two do not drift.
  • urls: added Documentation = "https://i2mint.github.io/uf/" (already live
    on the gh-pages branch).
  • .editorconfig: new, copied verbatim from the fleet reference.

Verified with uv build: the wheel METADATA emits License-Expression: MIT
plus the eight classifiers, with no conflicting license classifier. ruff check
and ruff format --check both clean.

Repo settings were also updated out-of-band (not branch-scoped): homepage set to
the docs URL, and topics added.

Deliberately out of scope

Left for later specialist passes, each a known finding:

  • The broad except ImportError: in uf/specs.pycurrently load-bearing
    for CI green
    . Something in the ju import chain raises ImportError in the
    GitHub runner environment (not yet identified; ipywidgets, lazy graphviz,
    and every ju/__init__ name were ruled out against the published wheel).
    Narrowing it now would surface that hidden ImportError as a CI failure. It
    deserves its own investigation.
  • 38 of 76 package doctests fail — illustrative Example: blocks written in
    doctest syntax that were never runnable. testpaths = ["tests"] is the only
    thing keeping them out of collection, so testpaths is intentionally
    unchanged here
    ; widening it before those are fixed would turn CI red.
  • No uf/py.typed, no CHANGELOG, CI is still uv-inline rather than the
    reusable-workflow stub.

Upstream note (informational, not uf's job): func_to_form_spec nesting its
result under "rjsf" by default is an easy trap for every consumer of ju.

https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475

`ju.rjsf.func_to_form_spec` defaults to `nest_under_field="rjsf"`, so it
returns `{"rjsf": {"schema": ..., "uiSchema": ...}}`. `_generate_spec` then
read `form_spec.get("schema", {})`, which always yielded `{}` — meaning every
generated RJSF form was empty whenever `ju` imported successfully. The empty
schema is served straight to the browser by `uf/routes.py` (`spec["schema"]`),
so this was user-facing, not just a test artifact.

Pass `nest_under_field=None` (via a dict merge, so caller overrides in
`_rjsf_config` still win) to get the flat shape `uf` expects — the same shape
the `_generate_basic_spec` fallback already emits.

Tests: 2 failed / 27 passed -> 29 passed.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
- license: replace the deprecated `[project.license] text = "mit"` table with
  the PEP 639 SPDX string `license = "MIT"` (canonical case). No
  `License :: OSI Approved ::` trove classifier is added — PyPI rejects that
  combination alongside an SPDX expression.
- keywords: fill in the empty placeholder.
- authors: fill in the empty placeholder.
- classifiers: add (were absent entirely, so the PyPI page had no trove
  metadata).
- description: "UI Fast" -> the README tagline, which actually says what the
  package does. The GitHub repo description is set to the same string so the
  two do not drift.
- urls: add `Documentation = "https://i2mint.github.io/uf/"` (already live on
  the gh-pages branch).
- .editorconfig: new, copied verbatim from the fleet reference.

Verified with `uv build`: METADATA emits `License-Expression: MIT` and the
eight classifiers, with no conflicting license classifier.

Claude-Session: https://claude.ai/code/session_01VipiLaG4xy7WctqY9w2475
@thorwhalen
thorwhalen merged commit b3ef821 into master Jul 30, 2026
12 checks passed
@thorwhalen
thorwhalen deleted the wads/fix-rjsf-spec-and-metadata branch July 30, 2026 17:54
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.

1 participant