docs(inline): correct inline post-processing example and fix Peewee parity (#1738)#2901
Open
jbbqqf wants to merge 4 commits into
Open
docs(inline): correct inline post-processing example and fix Peewee parity (#1738)#2901jbbqqf wants to merge 4 commits into
jbbqqf wants to merge 4 commits into
Conversation
…arity (pallets-eco#1738) The `inline_model_form_converter` docstrings in `flask_admin.contrib.sqla.view` and `flask_admin.contrib.peewee.view` advertised a `post_process` method on a converter subclass. That method name is never invoked anywhere in the codebase, so following the example is silently a no-op. The hook actually called by the SQLA converter is `InlineFormAdmin.postprocess_form` (see `flask_admin/contrib/sqla/form.py:1014,1139`). Update both docstrings to show the real hook, and add a regression test in `flask_admin/tests/sqla/test_inlineform.py` that subclasses `InlineFormAdmin`, contributes an extra field via `postprocess_form`, and asserts it lands on the generated inline form class. The Peewee inline converter never wired `postprocess_form` at all, so the same documented pattern was effectively broken there as well. Call `info.postprocess_form(child_form)` from `InlineModelConverter.contribute` to match the SQLA backend, and add a matching regression test in `flask_admin/tests/peeweemodel/test_basic.py`. Closes pallets-eco#1738.
CI's `typing` job (mypy in strict mode) flagged three things on the previous commit: 1. `flask_admin/contrib/peewee/form.py:334` -- the type: ignore on the `info.postprocess_form(child_form)` call only suppressed `[attr-defined]` but mypy now also raises `[arg-type]` (Any vs BaseForm) and `[assignment]` (BaseForm assigned into a slot mypy types as `BaseModelView | None`). Switch the comment to `[arg-type,assignment]` so the existing intent is preserved without the now-unused attr-defined ignore. 2. `flask_admin/tests/sqla/test_inlineform.py:404` -- `# type: ignore[no-untyped-def]` is unused; per project convention `disallow_untyped_defs` is off for test files, so just drop the ignore. 3. `flask_admin/tests/peeweemodel/test_basic.py:1199` -- same thing. 4. `flask_admin/tests/peeweemodel/test_basic.py:1210` -- `create_form_cls.model2_set` is a dynamically-named backref, so add `# type: ignore[attr-defined]` to mute the attr-defined error. Verified locally: - `mypy --python-version 3.10 flask_admin/contrib/peewee/form.py flask_admin/tests/sqla/test_inlineform.py flask_admin/tests/peeweemodel/test_basic.py` -> Success. - `pytest flask_admin/tests/peeweemodel/test_basic.py::test_inline_form_postprocess_form_hook flask_admin/tests/sqla/test_inlineform.py -q` -> 19 passed, 6 skipped.
676355e to
909b05c
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
The
inline_model_form_converterdocstrings inflask_admin.contrib.sqla.viewandflask_admin.contrib.peewee.viewadvertise a
post_processmethod on a converter subclass. That methodname is never invoked anywhere in the codebase, so following the
documented example is silently a no-op. The hook the SQLAlchemy
converter actually calls is
InlineFormAdmin.postprocess_form(seeflask_admin/contrib/sqla/form.py:1014,1139); theexamples/sqla_custom_inline_forms/main.py:132example uses that real hook.
Fixes #1738.
Context
flask_admin/contrib/sqla/view.py:213-224(pre-change) andflask_admin/contrib/peewee/view.py:112-123(pre-change) showed:Grepping the repo for
post_processreturns only those two docstringoccurrences -- nothing in the code path ever calls a method by that
name.
The real contract is on
InlineBaseFormAdmin:flask_admin/model/form.py:120-134definespostprocess_form(self, form_class)and the SQLA converter invokes itat
flask_admin/contrib/sqla/form.py:1014and:1139.The Peewee inline converter (
flask_admin/contrib/peewee/form.py:287-350)never invoked
postprocess_format all, so the documented pattern waseffectively broken on the Peewee backend as well.
Changes
flask_admin/contrib/sqla/view.py,flask_admin/contrib/peewee/view.py:rewrite the
inline_model_form_converterdocstring example to useInlineFormAdmin.postprocess_form(the hook the converter actuallyinvokes) and to pass the subclass through
inline_models.flask_admin/contrib/peewee/form.py: callinfo.postprocess_form(child_form)insideInlineModelConverter.contribute, mirroring the long-standing SQLAbehavior so the documented hook works on both backends.
flask_admin/tests/sqla/test_inlineform.py:add
test_inline_form_postprocess_form_hookthat subclassesInlineFormAdmin, contributes an extraStringFieldviapostprocess_form, and asserts the field lands on the generatedinline form class. Pins the documented contract.
flask_admin/tests/peeweemodel/test_basic.py:add a matching regression test that fails on
origin/main(the hookwas never called) and passes on this branch.
doc/changelog.rst: add[unreleased]entries for the documentationfix and the Peewee bug fix.
Reproduce BEFORE/AFTER yourself (copy-paste)
What I ran locally
needs
psycopg2):Edge cases
InlineFormAdminand contributeextrafield viapostprocess_forminline_models = (UserInfoInlineForm(UserInfo),)view._create_form_class.info.args[0]hasextraattributetest_inline_form_postprocess_form_hook[SQLAProvider-*]inline_models = (Model2InlineForm(Model2),)extraattributetest_inline_form_postprocess_form_hook(peewee)inline_models = (Model,)with noInlineFormAdminsubclasstest_inline_form/test_inline_form_required/test_inline_form_self/test_inline_form_base_classall still passInlineFormAdminreturning a custom form viaget_form()(skips the auto-generated path)info.get_form()returns non-Nonepostprocess_formafter assignmentpostprocess_formafter theif child_form is Nonebranch, matching the SQLA backend's structureRisk / blast radius
InlineModelConverter.contribute: now callsinfo.postprocess_form(child_form). The defaultInlineFormAdmin.postprocess_form(flask_admin/model/form.py:134)returns the form class unchanged, so existing call sites that never
overrode the hook see no diff. Behavior changes only for users who
do override the hook -- which is the previously-documented but
broken case we're fixing.
to import only because
psycopg2isn't installed in my dev env (it'sunrelated to this diff).
Release note
PR drafted with assistance from Claude Code (Anthropic). The change was
reviewed manually against flask-admin's source -- file:line references in
the body were checked against the cloned tree, and the copy-paste
BEFORE/AFTER reproducer block is the one I used during development;
reviewers can paste it verbatim.