Opened 12 months ago
Closed 12 months ago
#34807 closed Bug (fixed)
importing `django.forms` causes circular import error
Reported by: | Collin Anderson | Owned by: | Natalia Bidart |
---|---|---|---|
Component: | Forms | Version: | dev |
Severity: | Release blocker | Keywords: | |
Cc: | Nick Pope | Triage Stage: | Ready for checkin |
Has patch: | yes | Needs documentation: | no |
Needs tests: | no | Patch needs improvement: | no |
Easy pickings: | no | UI/UX: | no |
Description (last modified by )
circular import between forms and models and choices.
before [500e01073adda32d514962] you could import forms just fine.
git checkout 500e01073adda32d514962^ python3 -c"from django.db import models" # works fine python3 -c"from django import forms" # works fine
but since [500e01073adda32d514962] this hasn't worked due to circular import.
git checkout 500e01073adda32d514962 python3 -c"from django.db import models" # works fine python3 -c"from django import forms" # fails: Traceback (most recent call last): File "<string>", line 1, in <module> File "django/forms/__init__.py", line 6, in <module> from django.forms.boundfield import * # NOQA File "django/forms/boundfield.py", line 5, in <module> from django.forms.widgets import MultiWidget, Textarea, TextInput File "django/forms/widgets.py", line 15, in <module> from django.utils.choices import normalize_choices File "django/utils/choices.py", line 3, in <module> from django.db.models.enums import ChoicesMeta File "django/db/models/__init__.py", line 3, in <module> from django.db.models.aggregates import * # NOQA File "django/db/models/aggregates.py", line 5, in <module> from django.db.models.expressions import Case, Func, Star, Value, When File "django/db/models/expressions.py", line 12, in <module> from django.db.models import fields File "django/db/models/fields/__init__.py", line 18, in <module> from django.utils.choices import CallableChoiceIterator, normalize_choices ImportError: cannot import name 'CallableChoiceIterator' from partially initialized module 'django.utils.choices' (most likely due to a circular import) (django/utils/choices.py) python3 -c"from django.utils import choices" # also fails: Traceback (most recent call last): File "<string>", line 1, in <module> File "django/utils/choices.py", line 3, in <module> from django.db.models.enums import ChoicesMeta File "django/db/models/__init__.py", line 3, in <module> from django.db.models.aggregates import * # NOQA File "django/db/models/aggregates.py", line 5, in <module> from django.db.models.expressions import Case, Func, Star, Value, When File "django/db/models/expressions.py", line 12, in <module> from django.db.models import fields File "django/db/models/fields/__init__.py", line 10, in <module> from django import forms File "django/forms/__init__.py", line 6, in <module> from django.forms.boundfield import * # NOQA File "django/forms/boundfield.py", line 5, in <module> from django.forms.widgets import MultiWidget, Textarea, TextInput File "django/forms/widgets.py", line 15, in <module> from django.utils.choices import normalize_choices ImportError: cannot import name 'normalize_choices' from partially initialized module 'django.utils.choices' (most likely due to a circular import) (django/utils/choices.py)
Models has always had a dependency on Forms, but now Models depends on Forms depends on utils.choices
which depend on models.enums.ChoicesMeta
Summary of the circle: django.forms
-> forms.widgets
-> django.utils.choices
-> django.db.models.enums
-> models.__init__
-> models.aggregates
-> models.fields
-> django.forms
.
If django.db.models
is imported before forms then it happens to import fine because the order of imports happens to lines up perfectally, but it's very very fragile. models.__init__
-> models.aggregates
-> models.fields
-> django.forms
-> forms.widgets
-> django.utils.choices
-> django.db.models.enums
.
Change History (8)
comment:1 by , 12 months ago
Description: | modified (diff) |
---|---|
Severity: | Normal → Release blocker |
Triage Stage: | Unreviewed → Accepted |
comment:2 by , 12 months ago
Owner: | changed from | to
---|---|
Status: | new → assigned |
comment:3 by , 12 months ago
Cc: | added |
---|
comment:7 by , 12 months ago
Triage Stage: | Accepted → Ready for checkin |
---|
One thing that I don't understand is that when using a Django shell, the import works just fine. Tests also perform multiple
from django import forms
and they do not fail. OTOH, I can reproduce with the provided:Does anyone understand why the difference? (my main question is why this wasn't picked up by the tests or my IRL testing within a Django test project)
EDIT: as said in the description, the import works when issuing: