Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Too many values to unpack #59

Closed
Nixellion opened this issue Oct 25, 2023 · 5 comments
Closed

Too many values to unpack #59

Nixellion opened this issue Oct 25, 2023 · 5 comments

Comments

@Nixellion
Copy link

I believe this is an incompatibility with latest updates to WTForms 3.1.0, or maybe to something else in the flask ecosystem. Here's an error I get:

Traceback (most recent call last):
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask\app.py", line 2190, in wsgi_app
    response = self.full_dispatch_request()
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask\app.py", line 1486, in full_dispatch_request
    rv = self.handle_user_exception(e)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask\app.py", line 1484, in full_dispatch_request
    rv = self.dispatch_request()
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask\app.py", line 1469, in dispatch_request
    return self.ensure_sync(self.view_functions[rule.endpoint])(**view_args)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\base.py", line 69, in inner
    return self._run_view(f, *args, **kwargs)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\base.py", line 369, in _run_view
    return fn(self, *args, **kwargs)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\model\base.py", line 2124, in create_view
    return self.render(template,
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\base.py", line 308, in render
    return render_template(template, **kwargs)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask\templating.py", line 151, in render_template
    return _render(app, template, context)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask\templating.py", line 132, in _render
    rv = template.render(context)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\environment.py", line 1301, in render
    self.environment.handle_exception()
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\environment.py", line 936, in handle_exception
    raise rewrite_traceback_stack(source=source)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\model\create.html", line 3, in top-level template code
    {% from 'admin/lib.html' import extra with context %} {# backward compatible #}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\master.html", line 1, in top-level template code
    {% extends admin_base_template %}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\base.html", line 39, in top-level template code
    {% block page_body %}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\base.html", line 75, in block 'page_body'
    {% block body %}{% endblock %}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\model\create.html", line 22, in block 'body'
    {% block create_form %}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\model\create.html", line 23, in block 'create_form'
    {{ lib.render_form(form, return_url, extra(), form_opts) }}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\runtime.py", line 777, in _invoke
    rv = self._func(*arguments)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\lib.html", line 240, in template
    {% call form_tag(action=action) %}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\runtime.py", line 777, in _invoke
    rv = self._func(*arguments)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\lib.html", line 209, in template
    {{ caller() }}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\runtime.py", line 777, in _invoke
    rv = self._func(*arguments)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\lib.html", line 241, in template
    {{ render_form_fields(form, form_opts=form_opts) }}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\runtime.py", line 777, in _invoke
    rv = self._func(*arguments)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\lib.html", line 201, in template
    {{ render_field(form, f, kwargs) }}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\jinja2\runtime.py", line 777, in _invoke
    rv = self._func(*arguments)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\flask_admin\templates\bootstrap4\admin\lib.html", line 146, in template
    {{ field(**kwargs) | safe }}
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\wtfpeewee\fields.py", line 252, in __call__
    return self.widget(self, **kwargs)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\wtfpeewee\fields.py", line 153, in __call__
    return super(ChosenSelectWidget, self).__call__(field, **kwargs)
  File "d:\Projects\Web\project_name\project_name_refactor\venv\lib\site-packages\wtforms\widgets\core.py", line 365, in __call__
    for val, label, selected, render_kw in field.iter_choices():
ValueError: not enough values to unpack (expected 4, got 3)

Basically, from what I gather, previously field.iter_choices() didn't have the "render_kw" variable passed in the Select field, now it does.

Using WTForms<3.1.0 requirement works as a workaround, and does not seem to cause any other conflicts.
I will also propose a change to WTForms to retain backwards compatibility (not using unpacking and making render_kw optional)

@coleifer
Copy link
Owner

wtforms looks like they're up to some amateur nonsense -- issue here: wtforms/wtforms#692 - @davidism feel free to chime in. Looks like you broke flask-appbuilder (and by proxy apache airflow) with this backwards-incompatible change in a minor release.

@coleifer
Copy link
Owner

I've put a gross workaround in-place for now, thanks for reporting @Nixellion. This is starting to feel pretty normal from the flask-* "code shufflers" https://blog.miguelgrinberg.com/post/we-have-to-talk-about-flask

@Nixellion
Copy link
Author

Thanks. Is it on pypi already?

Yes, I've read that article and left a comment on it a few hours ago. I am afraid these code shuffling games can kill off flask ecosystem if they don't stop.

TLDR I think code shuffling is fine if it helps make working with the project easier, but not at the cost of wasting potentially millions of workhours of other people around the world. I am worried these changes may cause many extensions to die out, and without them flask will lose its main (one of) selling point - modularity and ecosystem of extensions. And its even before we remember that its not limited to just flask.

@coleifer
Copy link
Owner

coleifer commented Oct 25, 2023

Yeah, 3.0.5 should be up on pypi as of now.

As an aside, I'm glad I'm not the only who feels that way -- sometimes I wonder if I've just become old and curmudgeonly, but beyond my crustiness, it legitimately does seems like a lot of factors are in play.

  1. the rapid pace of changes to python the language
  2. the early adoption by many project maintainers of new language features
  3. tendency of some maintainers to shuffle things around with little-to-no regard for end users (e.g. @pallets, @pypa, etc)
  4. pervasive "old is bad, you should upgrade or you're bad" mindset
  5. async vs non-async split

I remember getting heated about some changes pallets was proposing a while back -- pallets/jinja#1121 -- and looks like my comment got deleted. Lol glad they walked that one back, that would've been a massive pain. My comment was luckily preserved by wayback:
im-1698254626490

Lol looking more closely it looks like old @davidism was at the helm of that one, too.

@Nixellion
Copy link
Author

Oh yeah, I'm sure many are on board with this, Miguel for example. However he also said in a follow up blog post that there was a lot of pushback not just from maintainers, but from community at large. Maybe we are getting old 😅

I think this needs to be split into 2 different themes though. One is "fast development pace, many changes", and another is "code shuffling". Miguel described this well in his article, it's fine making changes and breaking changes are ok, but it's not ok making a breaking change just because you didn't like the name of a variable. Or when introducing backwards compatibility is as simple as adding an alias for it. For example I "fixed" the issue of missing url_encode with this code in my project:

# region Patch flask login
import urllib.parse
import werkzeug.urls
werkzeug.urls.url_decode = werkzeug.urls.unquote
werkzeug.urls.url_encode = werkzeug.urls.urlencode
# endregion

How hard is it to add:

url_decode = unqoute
url_encode = urlencode

It's TWO LINES! And they don't even look too gross.

At the end of the day I just want things to work, and preferably without constantly re-learning how to do things. I am in the process of upgrading my flask project template and as part of it I considered "finally" switching to a "bigger better more standard" SQLAlchemy. And... I didn't. I am sticking with peewee, because it looks like SQLA released 2.0 version not long ago, and with it changed a lot of APIs and approaches. So it's kinda in this transitional state, not here nor there.

Just some praise for the stable and very well documented peewee 🙂 Can't live without it. Easier and more streamlined migrations is probably the only thing that I miss, or examples\best practices about how best to handle and automate migrations in a medium-large project.

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

No branches or pull requests

2 participants