#35046: BlankChoiceIterator causes AttributeError for some existing packages and projects --------------------------------------+------------------------ Reporter: hazho | Owner: nobody Type: Bug | Status: new Component: Utilities | Version: 5.0 Severity: Normal | Keywords: Triage Stage: Unreviewed | Has patch: 0 Needs documentation: 0 | Needs tests: 0 Patch needs improvement: 0 | Easy pickings: 1 UI/UX: 0 | --------------------------------------+------------------------ The iterators should have method __len__ ...! while this is not the case for (BlankChoiceIterator) in the current version of Django (5.0), this is why the following error raised: AttributeError: 'BlankChoiceIterator' object has no attribute '__len__'. Did you mean: '__le__'?
to solve this, simply the BlankChoiceIterator class should have the method __len__ returning 0 as indication for emptiness. this is important because the package maintainer or project author may not find the way to update their code accordingly, for example the projects depend on django-countries would have the following trace raised (note there is no obvious indication where in the project code is the main causer that calls __len__ of BlankChoiceIterator objects: {{{ Traceback (most recent call last): File "C:\env_django_simple_payment_system\Lib\site- packages\django\core\handlers\exception.py", line 55, in inner response = get_response(request) ^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\core\handlers\base.py", line 197, in _get_response response = wrapped_callback(request, *callback_args, **callback_kwargs) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\django_simple_payment_system\wallets\views.py", line 38, in index return render(request, template_path, context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\shortcuts.py", line 24, in render content = loader.render_to_string(template_name, context, request, using=using) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\loader.py", line 62, in render_to_string return template.render(context, request) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\backends\django.py", line 61, in render return self.template.render(context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 171, in render return self._render(context) ^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 163, in _render return self.nodelist.render(context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 1000, in render return SafeString("".join([node.render_annotated(context) for node in self])) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 961, in render_annotated return self.render(context) ^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\loader_tags.py", line 210, in render return template.render(context) ^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 173, in render return self._render(context) ^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 163, in _render return self.nodelist.render(context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 1000, in render return SafeString("".join([node.render_annotated(context) for node in self])) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 961, in render_annotated return self.render(context) ^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\defaulttags.py", line 241, in render nodelist.append(node.render_annotated(context)) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 961, in render_annotated return self.render(context) ^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 1065, in render return render_value_in_context(output, context) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\template\base.py", line 1042, in render_value_in_context value = str(value) ^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\forms\utils.py", line 79, in __str__ return self.as_widget() ^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\forms\boundfield.py", line 95, in as_widget attrs = self.build_widget_attrs(attrs, widget) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\forms\boundfield.py", line 270, in build_widget_attrs widget.use_required_attribute(self.initial) File "C:\env_django_simple_payment_system\Lib\site- packages\django\forms\widgets.py", line 781, in use_required_attribute first_choice = next(iter(self.choices), None) ^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django_countries\widgets.py", line 29, in get_choices self._choices: ChoiceList = list(self._choices) ^^^^^^^^^^^^^^^^^^^ File "C:\env_django_simple_payment_system\Lib\site- packages\django\utils\functional.py", line 188, in __wrapper__ return getattr(result, __method_name)(*args, **kw) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ AttributeError: 'BlankChoiceIterator' object has no attribute '__len__'. Did you mean: '__le__'? }}} the solution can be as the following: {{{ # django/utils/choices.py class BlankChoiceIterator(BaseChoiceIterator): """Iterator to lazily inject a blank choice.""" # existing code def __len__(self): return 0 }}} -- Ticket URL: <https://code.djangoproject.com/ticket/35046> Django <https://code.djangoproject.com/> The Web framework for perfectionists with deadlines. -- You received this message because you are subscribed to the Google Groups "Django updates" group. To unsubscribe from this group and stop receiving emails from it, send an email to django-updates+unsubscr...@googlegroups.com. To view this discussion on the web visit https://groups.google.com/d/msgid/django-updates/0107018c7a30cea5-ebffe305-7941-418d-8ec5-a561360ee2c8-000000%40eu-central-1.amazonses.com.