django-formtools: Infinite Recursion possible in 2.4
We have a condition_dict containing the following function:
def need_further_steps(wizard):
data = wizard.get_cleaned_data_for_step("0") or {}
if data.get("no_invoices_needed", False):
return False
return True
The call to WizardView.get_cleaned_data_for_step then calls WizardView.get_form, which used to reference self.form_list, but the following commit changes this to self.get_form_list(), which then calls the user-supplied condition_dict functions, which then calls our need_further_steps function above, which calls WizardView.get_cleaned_data_for_step, and so on ad infinitum.
https://github.com/jazzband/django-formtools/commit/533a83053deab2adeb72de079e813aae78b03c1a
Perhaps our custom condition function is bad, but it doesn’t seem too unreasonable?
About this issue
- Original URL
- State: closed
- Created 2 years ago
- Reactions: 2
- Comments: 41 (23 by maintainers)
Commits related to this issue
- Possible solution for #220 This shows a possible approach we can use to fix the infinite recursion that can be triggered by referring to step data from condition_dict callables. — committed to schinckel/django-formtools by schinckel 2 years ago
- Require django-formtools < 2.4 Issue with infinite recursion in version 2.4, see https://github.com/jazzband/django-formtools/issues/220 — committed to CosmosTUe/Cosmos by bcvandendool 2 years ago
- Fixing #220 — committed to violuke/django-formtools by violuke 2 years ago
- Fix infinite recursion error #220 This removes the undocumented `get_form_list` since the process of repeatedly and dynamically generating an OrderedDict of steps/forms pairs leads to infinite recurs... — committed to jsma/django-formtools by jsma 2 years ago
- Merge remote-tracking branch 'greenlightgo/fix-infinite-recursion-220' * greenlightgo/fix-infinite-recursion-220: Fix infinite recursion error #220 — committed to fdemmer/django-formtools by fdemmer 2 years ago
- Add test_form_condition_callable Skipped for now as this feature broke in 533a83053deab2adeb72de079e813aae78b03c1a see: https://github.com/jazzband/django-formtools/issues/220 — committed to fdemmer/django-formtools by fdemmer 2 years ago
- Update to Django 3.2 and update Python packages I can't currently update to Django 4.0 because django-formtools 2.4 includes a bug that breaks our usage case of conditional form steps on the Outreach... — committed to outreachy/website by deleted user 2 years ago
- Update to Django 3.2 and update Python packages I can't currently update to Django 4.0 because django-formtools 2.4 includes a bug that breaks our usage case of conditional form steps on the Outreach... — committed to outreachy/website by deleted user 2 years ago
- Pin django-formtools to 2.3 See https://github.com/jazzband/django-formtools/issues/220 for more — committed to DemocracyClub/EveryElection by symroe a year ago
- fix: regression bug in https://github.com/jazzband/django-formtools/issues/220 — committed to basxsoftwareassociation/basxconnect by saemideluxe a year ago
- Fixes #220 - Avoid inifinite recursion while getting wizard form list — committed to claudep/django-formtools by claudep a year ago
- Fixes #220 - Avoid inifinite recursion while getting wizard form list — committed to claudep/django-formtools by claudep a year ago
- Pin django-formtools to 2.3 See jazzband/django-formtools#220 for more — committed to DemocracyClub/EveryElection by VirginiaDooley a year ago
- Pin django-formtools to 2.3 See jazzband/django-formtools#220 for more — committed to DemocracyClub/EveryElection by VirginiaDooley a year ago
- Pin django-formtools to 2.3 See jazzband/django-formtools#220 for more — committed to DemocracyClub/EveryElection by VirginiaDooley a year ago
- Update django-formtools to 2.4.1 django-formtools committed a fix in version 2.4.1 for the regression causing our initial application form to not work. Original bug: https://github.com/jazzband/dja... — committed to outreachy/website by deleted user 7 months ago
- Update django-formtools to 2.4.1 django-formtools committed a fix in version 2.4.1 for the regression causing our initial application form to not work. Original bug: https://github.com/jazzband/dja... — committed to outreachy/website by deleted user 7 months ago
Please revert 533a83053, which introduced a major bug and was not a proper solution for the new feature request (to dynamically add forms that aren’t in the initial
form_list). For those that require this new feature, please provide a working example of your use cases and how you were doing this prior to 2.4. A proper API needs to be created and tested for this new feature request, without breaking existing documented functionality. That has not been done yet. A proper API shouldn’t require any hacks around infinite recursion errors, it should be designed so these errors are impossible.I’ve just submitted a PR that attempts a more complete fix for this problem. Please have a look and give it a test if you’ve got time.
A reason could be that version 2.4.0 added official support for django v4
Maybe a version 2.3.1 could be released with the old behaviour and official django v4 support? So we can pin to
<2.4until the issue is somehow resolved and upgrade/use django v4.The latter - to come up with a proper solution.
@martey, it should be reverted because 2.4 is a broken release that breaks real projects and costs people valuable time and money. It’s not very reasonable to expect everyone to find out the hard way that 2.4 is broken, find this issue, and then downgrade to 2.3, when reverting could avoid all of that. To be clear, we don’t need to come up with a comprehensive solution for the infinite recursion bug. The changeset that introduced the bug simply needs to be reverted. Once that is done, a comprehensive solution to the feature request (to be able to dynamically add forms that are not present in
form_list) would need to be developed, documented, and tested before being included in a future release.@schinckel, are you saying you don’t have time for reverting the commit or just that you do not have time to work on a proper solution for the feature request? There is already #222 for reverting the change. In my opinion, 2.4 should be yanked from PyPI in favor of the next release. I could submit a PR to update the changelog. Let us know how we can help. Thanks!
The fix of #168 has caused this problem. My understanding is that you should be using the
conditiion_dictto vary which steps are in the wizard and which are not. I can see why overridingget_form_list()would seem like a nice alternative (and maybe simpler to use), but by changingget_form()to useget_form_list()and solve the request of #168, this makes it impossible to have conditions which look at prior form steps as part of their conditions and therefore breaks what is probably one of the most common use-cases of this package.My opinion is that 533a83053deab2adeb72de079e813aae78b03c1a should be reverted as it tries to allow the same problem to be solved in a new, previously-not-possible, way and breaks the original way of solving the same problem that’s been part of this great package for years.
Thanks for your help, we’ve also had to pin 2.3 due to this being a breaking change for our use of the package.
Yeah, that looks okay to me.
The original use case was to dynamically inject forms: specifically given the input from step A, run n instances of step B with different data, as “sub-steps”.
And in an ideal world, SemVer would be used so people could understand version numbers and use modern package managers like Poetry properly. This being a breaking change could then be safely introduced using version 3.0.0 instead of 2.4.0, if it was wanted (not that I’m sure it should be tbh). Having come from other languages to Python in the last few years, the Python community seems quite out of sync with the rest on the SemVer front and SemVer is really damn handy when managing dependencies.
I’ll have a stare at this later + try and understand it (and invite everyone else to) - I (or someone else), should add a test to this for modifying get_form_list() as well so we have both cases.
EDIT: Thanks for making an actual test; I’m pressed for free time, so it’s really helpful to have a working example to start from.
I agree that a project-wide Django setting is too broad, but this could be fixed by adding a
dynamic_form_listvariable toWizardViewthat defaults toFalse.