Opened 6 months ago

Closed 6 months ago

Last modified 6 months ago

#36252 closed Bug (fixed)

Duplicate entries in automatic imports in Django Shell

Reported by: Raffaella Owned by: hesham hatem
Component: Core (Management commands) Version: 5.2
Severity: Release blocker Keywords: shell
Cc: Raffaella 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

When customizing the automatic imports into the shell by adding the same import twice:

from django.core.management.commands import shell


class Command(shell.Command):
    def get_auto_imports(self):
        return super().get_auto_imports() + [
            "django.urls.reverse",
            "django.urls.reverse",
        ]

After opening the shell, while the total number of imports is correct, the reverse import is displayed twice in the output:

12 objects imported automatically:

  from project.newsletter.models import SubscriptionNotification, Subscription, Post, Category
  from django.contrib.sessions.models import Session
  from django.contrib.sites.models import Site
  from django.contrib.contenttypes.models import ContentType
  from django.contrib.auth.models import User, Group, Permission
  from django.contrib.admin.models import LogEntry
  from django.urls import reverse, reverse

Change History (13)

comment:1 by hesham hatem, 6 months ago

Owner: set to hesham hatem
Status: newassigned

comment:2 by hesham hatem, 6 months ago

Has patch: set

comment:3 by Clifford Gama, 6 months ago

Resolution: worksforme
Status: assignedclosed

Thanks Raffaella for the report and for testing. However, I can't replicate this with the provided information. For me, imports repeated in get_auto_imports are displayed only once, no matter how many times they are repeated. I tried this with verbosity of 2 and 3 and on ipython and regular python shell.

in reply to:  3 comment:4 by Raffaella, 6 months ago

Replying to Clifford Gama:

Thanks Raffaella for the report and for testing. However, I can't replicate this with the provided information. For me, imports repeated in get_auto_imports are displayed only once, no matter how many times they are repeated. I tried this with verbosity of 2 and 3 and on ipython and regular python shell.

Thanks Cliffort for your reply.
I tried it on a different project, and I do have multiple imports of the same reverse when running python manage.py shell -v=2 with this code

from django.core.management.commands import shell


class Command(shell.Command):
    def get_auto_imports(self):
        return super().get_auto_imports() + [
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
        ]

When I open the shell:

9 objects imported automatically:

  from page.models import Tag, Blog
  from django.contrib.sessions.models import Session
  from django.contrib.contenttypes.models import ContentType
  from django.contrib.auth.models import User, Group, Permission
  from django.contrib.admin.models import LogEntry
  from django.urls import reverse, reverse, reverse, reverse, reverse, reverse

My current django version is 5.2b1.
The number of the 9 imports is correct.

comment:5 by Natalia Bidart, 6 months ago

Thank you Raffaella and Clifford for the reporting and handling of this ticket. I can't reproduce either, using Django main, with a custom shell command like this:

from django.core.management.commands import shell


class Command(shell.Command):
    def get_auto_imports(self):
        return super().get_auto_imports() + [
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
            "django.urls.reverse",
        ]

I get (models are custom from my django test project where I do general ticket triage):

$ python -Wall manage.py shell --verbosity=2
30 objects imported automatically:

  from django.contrib.admin.models import LogEntry
  from django.contrib.auth.models import Group, Permission, User
  from django.contrib.contenttypes.models import ContentType
  from django.contrib.sessions.models import Session
  from django.urls import reverse

  from abstractmodels.models import ArticlePage, Page
  from complexapp.models.a import ModelA
  from complexapp.models.b import ModelB
  from complexapp.models.c import ModelC
  from generatedapp.models import (Author, AuthorProfile, Book, BookGenre,
                                   Genre, Review)
  from testapp.models import (BasicModel, CollidingModelName, Course, Student,
                              Ticket36031Model, UUIDModel, VulnerableModel)
  from ticket_35928.models import (BlogPost, CollidingModelName, Comment,
                                   Image, Product, TaggedItem)

Python 3.13.2 (main, Feb  5 2025, 08:49:06) [GCC 13.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
(InteractiveConsole)
>>> 

comment:6 by Natalia Bidart, 6 months ago

Resolution: worksforme
Severity: NormalRelease blocker
Status: closednew
Triage Stage: UnreviewedAccepted

On a second look, I'm able to reproduce. I think the key difference is having isort installed or not. Details:

  • When building the auto_imports dict we are accumulating duplicating modules (output reduced for easier reading):
    (Pdb) pprint(auto_imports)
    defaultdict(<class 'list'>, {
                 'django.contrib.admin.models': [('LogEntry',
                                                  <class 'django.contrib.admin.models.LogEntry'>)],
                 'django.contrib.auth.models': [('User',
                                                 <class 'django.contrib.auth.models.User'>),
                                                ('Group',
                                                 <class 'django.contrib.auth.models.Group'>),
                                                ('Permission',
                                                 <class 'django.contrib.auth.models.Permission'>)],
                 'django.contrib.contenttypes.models': [('ContentType',
                                                         <class 'django.contrib.contenttypes.models.ContentType'>)],
                 'django.contrib.sessions.models': [('Session',
                                                     <class 'django.contrib.sessions.models.Session'>)],
                 'django.urls': [('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>),
                                 ('reverse', <function reverse at 0x7d9628a5a700>)]})
    
  • The above needs some cleanup, though the namespace dictionary items are properly unique, see:
    (Pdb) pprint(namespace)
    {'ContentType': <class 'django.contrib.contenttypes.models.ContentType'>,
     'Group': <class 'django.contrib.auth.models.Group'>,
     'LogEntry': <class 'django.contrib.admin.models.LogEntry'>,
     'Permission': <class 'django.contrib.auth.models.Permission'>,
     'Session': <class 'django.contrib.sessions.models.Session'>,
     'User': <class 'django.contrib.auth.models.User'>,
     'reverse': <function reverse at 0x7d9628a5a700>}
    
  • The resulting import_string has the duplicated entries, but later isort would clean that up:
    (Pdb) pprint(import_string)
    ('  from ticket_35928.models import TaggedItem, CollidingModelName, Image, '
     'Product, BlogPost, Comment\n'
     '  from testapp.models import UUIDModel, VulnerableModel, Course, Student, '
     'Ticket36031Model, CollidingModelName, BasicModel\n'
     '  from generatedapp.models import Review, AuthorProfile, BookGenre, Genre, '
     'Book, Author\n'
     '  from complexapp.models.c import ModelC\n'
     '  from complexapp.models.b import ModelB\n'
     '  from complexapp.models.a import ModelA\n'
     '  from abstractmodels.models import ArticlePage, Page\n'
     '  from django.contrib.sessions.models import Session\n'
     '  from django.contrib.contenttypes.models import ContentType\n'
     '  from django.contrib.auth.models import User, Group, Permission\n'
     '  from django.contrib.admin.models import LogEntry\n'
     '  from django.urls import reverse, reverse, reverse, reverse, reverse, '
     'reverse, reverse, reverse, reverse')
    

Accepting since this should properly import and show unique entries, with or without isort.

comment:7 by Natalia Bidart, 6 months ago

Needs tests: set
Patch needs improvement: set
Summary: Duplicate Display of Imports in Django ShellDuplicate entries in automatic imports in Django Shell

comment:8 by Clifford Gama, 6 months ago

Thanks Rafaella for the follow-up and Natalia for testing. Indeed, I get duplicate entries without isort.

comment:9 by Raffaella, 6 months ago

Thank you Natalia for your suggestions

Last edited 6 months ago by Raffaella (previous) (diff)

comment:10 by Natalia Bidart, 6 months ago

Needs tests: unset
Triage Stage: AcceptedReady for checkin

comment:11 by Natalia Bidart, 6 months ago

Patch needs improvement: unset

comment:12 by nessita <124304+nessita@…>, 6 months ago

Resolution: fixed
Status: newclosed

In e804a07:

Fixed #36252 -- Handled duplicate automatic imports in the shell command.

comment:13 by Natalia <124304+nessita@…>, 6 months ago

In 1d8696bf:

[5.2.x] Fixed #36252 -- Handled duplicate automatic imports in the shell command.

Backport of e804a07d76fc85468f27f7130ae1442fabcd650d from main.

Note: See TracTickets for help on using tickets.
Back to Top