pallets-eco / flask-admin

Simple and extensible administrative interface framework for Flask
https://flask-admin.readthedocs.io
BSD 3-Clause "New" or "Revised" License
5.8k stars 1.58k forks source link

StrinField incompatible with wtforms>=3.2.1 #2548

Closed om-henners closed 1 month ago

om-henners commented 1 month ago

After updating to wtforms 3.2.1I get the following errors:

/usr/opt/venv/lib/python3.11/site-packages/werkzeug/test.py:1162: in get
    return self.open(*args, **kw)
/usr/opt/venv/lib/python3.11/site-packages/flask/testing.py:235: in open
    response = super().open(
/usr/opt/venv/lib/python3.11/site-packages/werkzeug/test.py:1116: in open
    response_parts = self.run_wsgi_app(request.environ, buffered=buffered)
/usr/opt/venv/lib/python3.11/site-packages/werkzeug/test.py:988: in run_wsgi_app
    rv = run_wsgi_app(self.application, environ, buffered=buffered)
/usr/opt/venv/lib/python3.11/site-packages/werkzeug/test.py:1264: in run_wsgi_app
    app_rv = app(environ, start_response)
/usr/opt/venv/lib/python3.11/site-packages/flask/app.py:1498: in __call__
    return self.wsgi_app(environ, start_response)
/usr/opt/venv/lib/python3.11/site-packages/flask/app.py:1476: in wsgi_app
    response = self.handle_exception(e)
/usr/opt/venv/lib/python3.11/site-packages/flask/app.py:1473: in wsgi_app
    response = self.full_dispatch_request()
/usr/opt/venv/lib/python3.11/site-packages/flask/app.py:882: in full_dispatch_request
    rv = self.handle_user_exception(e)
/usr/opt/venv/lib/python3.11/site-packages/flask/app.py:880: in full_dispatch_request
    rv = self.dispatch_request()
/usr/opt/venv/lib/python3.11/site-packages/flask/app.py:865: in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)  # type: ignore[no-any-return]
/usr/opt/venv/lib/python3.11/site-packages/flask_admin/base.py:69: in inner
    return self._run_view(f, *args, **kwargs)
/usr/opt/venv/lib/python3.11/site-packages/flask_admin/base.py:369: in _run_view
    return fn(self, *args, **kwargs)
/usr/opt/venv/lib/python3.11/site-packages/flask_admin/model/base.py:2149: in edit_view
    form = self.edit_form(obj=model)
/usr/opt/venv/lib/python3.11/site-packages/flask_admin/model/base.py:1340: in edit_form
    return self._edit_form_class(get_form_data(), obj=obj)
/usr/opt/venv/lib/python3.11/site-packages/wtforms/form.py:209: in __call__
    return type.__call__(cls, *args, **kwargs)
/usr/opt/venv/lib/python3.11/site-packages/flask_admin/form/__init__.py:22: in __init__
    super(BaseForm, self).__init__(formdata=formdata, obj=obj, prefix=prefix, **kwargs)
/usr/opt/venv/lib/python3.11/site-packages/wtforms/form.py:281: in __init__
    super().__init__(self._unbound_fields, meta=meta_obj, prefix=prefix)
/usr/opt/venv/lib/python3.11/site-packages/wtforms/form.py:49: in __init__
    field = meta.bind_field(self, unbound_field, options)
/usr/opt/venv/lib/python3.11/site-packages/wtforms/meta.py:28: in bind_field
    return unbound_field.bind(form=form, **options)
/usr/opt/venv/lib/python3.11/site-packages/wtforms/fields/core.py:387: in bind
    return self.field_class(*self.args, **kw)
_ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ _ 

self = <wtforms.fields.simple.StringField object at 0x74b98557b310>, label = 'Code'
validators = [<flask_admin.contrib.sqla.validators.Unique object at 0x74b981d03b50>, <wtforms.validators.Optional object at 0x74b981d02150>]
filters = [<function AdminModelConverter.conv_String.<locals>.<lambda> at 0x74b982267420>], description = None, id = None, default = None, widget = None, render_kw = None, name = 'code'
_form = <flask_admin.contrib.sqla.form.RegionForm object at 0x74b982af8750>, _prefix = '', _translations = None, _meta = None

    def __init__(
        self,
        label=None,
        validators=None,
        filters=(),
        description="",
        id=None,
        default=None,
        widget=None,
        render_kw=None,
        name=None,
        _form=None,
        _prefix="",
        _translations=None,
        _meta=None,
    ):
        """
        Construct a new field.

        :param label:
            The label of the field.
        :param validators:
            A sequence of validators to call when `validate` is called.
        :param filters:
            A sequence of callable which are run by :meth:`~Field.process`
            to filter or transform the input data. For example
            ``StringForm(filters=[str.strip, str.upper])``.
            Note that filters are applied after processing the default and
            incoming data, but before validation.
        :param description:
            A description for the field, typically used for help text.
        :param id:
            An id to use for the field. A reasonable default is set by the form,
            and you shouldn't need to set this manually.
        :param default:
            The default value to assign to the field, if no form or object
            input is provided. May be a callable.
        :param widget:
            If provided, overrides the widget used to render the field.
        :param dict render_kw:
            If provided, a dictionary which provides default keywords that
            will be given to the widget at render time.
        :param name:
            The HTML name of this field. The default value is the Python
            attribute name.
        :param _form:
            The form holding this field. It is passed by the form itself during
            construction. You should never pass this value yourself.
        :param _prefix:
            The prefix to prepend to the form name of this field, passed by
            the enclosing form during construction.
        :param _translations:
            A translations object providing message translations. Usually
            passed by the enclosing form during construction. See
            :doc:`I18n docs <i18n>` for information on message translations.
        :param _meta:
            If provided, this is the 'meta' instance from the form. You usually
            don't pass this yourself.

        If `_form` isn't provided, an :class:`UnboundField` will be
        returned instead. Call its :func:`bind` method with a form instance and
        a name to construct the field.
        """
        if _translations is not None:
            self._translations = _translations

        if _meta is not None:
            self.meta = _meta
        elif _form is not None:
            self.meta = _form.meta
        else:
            raise TypeError("Must provide one of _form or _meta")

        self.default = default
        self.description = description
        self.render_kw = render_kw
        self.filters = filters
        self.flags = Flags()
        self.name = _prefix + name
        self.short_name = name
        self.type = type(self).__name__

        self.check_validators(validators)
        self.validators = validators or self.validators

        self.id = id or self.name
        self.label = Label(
            self.id,
            label
            if label is not None
            else self.gettext(name.replace("_", " ").title()),
        )

        if widget is not None:
            self.widget = widget

        for v in itertools.chain(self.validators, [self.widget]):
            flags = getattr(v, "field_flags", {})

>           for k, v in flags.items():
E           AttributeError: 'tuple' object has no attribute 'items'

/usr/opt/venv/lib/python3.11/site-packages/wtforms/fields/core.py:133: AttributeError

Environment:

Adham-neo commented 1 month ago

issue when using form_choices for dropdown resulting in this error:

(downgrading wtforms to 3.1.2 fixed the issue)

Traceback (most recent call last):
  File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 1498, in __call__
    return self.wsgi_app(environ, start_response)
  File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 1476, in wsgi_app
    response = self.handle_exception(e)
  File "/usr/local/lib/python3.11/site-packages/flask_cors/extension.py", line 176, in wrapped_function
    return cors_after_request(app.make_response(f(*args, **kwargs)))
  File "/usr/local/lib/python3.11/site-packages/flask_restx/api.py", line 672, in error_router
    return original_handler(e)
  [Previous lines repeated multiple times]
  File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 880, in full_dispatch_request
    rv = self.dispatch_request()
  File "/usr/local/lib/python3.11/site-packages/flask/app.py", line 865, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "/usr/local/lib/python3.11/site-packages/flask_admin/base.py", line 76, in inner
    return self._run_view(f, *args, **kwargs)
  File "/usr/local/lib/python3.11/site-packages/flask_admin/model/base.py", line 2209, in edit_view
    return self.render(template, **kwargs)
  File "/usr/local/lib/python3.11/site-packages/flask/templating.py", line 150, in render_template
    return _render(app, template, context)
  File "/usr/local/lib/python3.11/site-packages/flask/templating.py", line 131, in _render
    rv = template.render(context)
  File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 1301, in render
    self.environment.handle_exception()
  File "/usr/local/lib/python3.11/site-packages/jinja2/environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "/usr/local/lib/python3.11/site-packages/flask_admin/templates/bootstrap4/admin/model/edit.html", line 3, in top-level template code
    {% from 'admin/lib.html' import extra with context %}
  File "/usr/local/lib/python3.11/site-packages/flask_admin/templates/bootstrap4/admin/model/edit.html", line 33, in block 'edit_form'
    {{ lib.render_form(form, return_url, extra(), form_opts) }}
  File "/usr/local/lib/python3.11/site-packages/jinja2/runtime.py", line 777, in _invoke
    rv = self._func(*arguments)
  File "/usr/local/lib/python3.11/site-packages/flask_admin/templates/bootstrap4/admin/lib.html", line 146, in template
    {{ field(**kwargs) | safe }}
  File "/usr/local/lib/python3.11/site-packages/wtforms/fields/core.py", line 164, in __call__
    return self.meta.render_field(self, kwargs)
  File "/usr/local/lib/python3.11/site-packages/wtforms/meta.py", line 64, in render_field
    return field.widget(field, **render_kw)
  File "/usr/local/lib/python3.11/site-packages/flask_admin/form/widgets.py", line 23, in __call__
    return super(Select2Widget, self).__call__(field, **kwargs)
  File "/usr/local/lib/python3.11/site-packages/wtforms/widgets/core.py", line 374, in __call__
    val, label, selected, render_kw = choice
ValueError: not enough values to unpack (expected 4, got 3)

cc: @ronyriachy

samuelhwilliams commented 1 month ago

Please could you provide a minimal reproduction code example to assist with debugging. Thanks :)

samuelhwilliams commented 1 month ago

Also can you please test this with v2.0.0a - I believe this may have been fixed as well?

ronyriachy commented 1 month ago

Hello, The flask version is 2.0.0a0. In order to reproduce the issue, add form_choices to the view class with any options and open the create or edit view. It gives an error if WTForms version is 3.2.1 (which is the newest version).

When we downgraded to 3.1.2, it worked fine

On Sat, 26 Oct 2024, 19:20 Samuel Williams, @.***> wrote:

Also can you please test this with v2.0.0a - I believe this may have been fixed as well?

— Reply to this email directly, view it on GitHub https://github.com/pallets-eco/flask-admin/issues/2548#issuecomment-2439639056, or unsubscribe https://github.com/notifications/unsubscribe-auth/A3VO4UL53HJ244NH6PXL65LZ5O6LPAVCNFSM6AAAAABQQCQ4QCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMZZGYZTSMBVGY . You are receiving this because you were mentioned.Message ID: @.***>

samuelhwilliams commented 1 month ago

I think yours and @Adham-neo's issue is different than the one in the original post of this issue, however should be fixed by https://github.com/pallets-eco/flask-admin/pull/2551 that I will look to get in shortly.

samuelhwilliams commented 1 month ago

Both of the issues mentioned in this thread should be fixed by either v2.0.0a0 or v2.0.0a1 (just published).

I will close this off for now.

Thanks for reporting it 🙇

ronyriachy commented 1 month ago

Thanks to you!

On Sat, 26 Oct 2024, 21:16 Samuel Williams, @.***> wrote:

Both of the issues mentioned in this thread should be fixed by either v2.0.0a0 or v2.0.0a1 (just published).

I will close this off for now.

Thanks for reporting it 🙇

— Reply to this email directly, view it on GitHub https://github.com/pallets-eco/flask-admin/issues/2548#issuecomment-2439681697, or unsubscribe https://github.com/notifications/unsubscribe-auth/A3VO4UMHKD62UN5LIKD6XUTZ5PL6NAVCNFSM6AAAAABQQCQ4QCVHI2DSMVQWIX3LMV43OSLTON2WKQ3PNVWWK3TUHMZDIMZZGY4DCNRZG4 . You are receiving this because you were mentioned.Message ID: @.***>