2

So, this is an extension of what I asked last week (Why do I need to import a class within this class, instead of at the top of the file?) but after extensive debugging, I feel like it might warrant a new question.

I have a number of modules, all with imports. I suspect there may be a circular import but I haven't been able to find it.

Here's the weird thing:

In one models.py file, I have:

from django.db import models
from django.core.exceptions import ObjectDoesNotExist
from heythere.models import Notification as HeyThere
from heythere.models import NotificationManager as HeyThereManager
from django.contrib.auth.models import User

then some model definitions, including one with a method:

def to_user(self):
    try:
        return User.objects.get(username=str(self.username))
    except ObjectDoesNotExist:
        return None

and a little further down:

from ownership.apps.Assets.models import Item

When it's like this, I get AttributeError: 'NoneType' object has no attribute 'objects' (referring to User). So it's set to None, somehow, as opposed to raising a global name XXX is not defined.

BUT THEN, I tried accessing the User right after the import:

me = User.objects.get(username='xxxx')
print me

It printed correctly upon running runserver, so I know it can access User there, but then gave me the error message ImportError: cannot import name Item. How did simply accessing the model cause an import error? (FWIW, Item does have a number of FK relations to User)

What gives?

Traceback when User.objects.get() is included:

  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/utils/autoreload.py", line 93, in wrapper
    fn(*args, **kwargs)
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/core/management/commands/runserver.py", line 101, in inner_run
    self.validate(display_num_errors=True)
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/core/management/base.py", line 310, in validate
    num_errors = get_validation_errors(s, app)
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/core/management/validation.py", line 34, in get_validation_errors
    for (app_name, error) in get_app_errors().items():
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/db/models/loading.py", line 196, in get_app_errors
    self._populate()
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/db/models/loading.py", line 78, in _populate
    self.load_app(app_name)
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/db/models/loading.py", line 99, in load_app
    models = import_module('%s.models' % app_name)
  File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/utils/importlib.py", line 40, in import_module
    __import__(name)
  File "/Users/xxxxx/code/ownership/ownership/apps/Assets/models.py", line 12, in <module>
    import permissions
  File "/Users/xxxxx/code/ownership/ownership/apps/Assets/permissions.py", line 4, in <module>
    from ownership.apps.Shared.models import Person
  File "/Users/xxxxx/code/ownership/ownership/apps/Shared/models.py", line 87, in <module>
    from ownership.apps.Assets.models import Item
ImportError: cannot import name Item

And without (how the code should work):

Environment:


Request Method: POST
Request URL: http://localhost:8000/application/new

Django Version: 1.6.1
Python Version: 2.7.2
Installed Applications:
('suit',
 'south',
 'django.contrib.auth',
 'django.contrib.contenttypes',
 'django.contrib.sessions',
 'django.contrib.sites',
 'django.contrib.redirects',
 'django.contrib.messages',
 'django.contrib.staticfiles',
 'django.contrib.admin',
 'rest_framework',
 'ldap_sync',
 'crispy_forms',
 'ownership.apps.Catalog',
 'ownership.apps.Assets',
 'ownership.apps.Shared',
 'ownership.libs.display',
 'django_tables2',
 'haystack',
 'autocomplete_light',
 'reversion',
 'heythere',
 'polymorphic',
 'django_extensions',
 'debug_toolbar')
Installed Middleware:
('django.middleware.common.CommonMiddleware',
 'django.contrib.sessions.middleware.SessionMiddleware',
 'django.middleware.csrf.CsrfViewMiddleware',
 'django.contrib.auth.middleware.AuthenticationMiddleware',
 'django.contrib.messages.middleware.MessageMiddleware',
 'django.contrib.redirects.middleware.RedirectFallbackMiddleware',
 'django.middleware.transaction.TransactionMiddleware',
 'reversion.middleware.RevisionMiddleware',
 'ownership.libs.shibboleth.CustomHeaderMiddleware',
 'debug_toolbar.middleware.DebugToolbarMiddleware')


Traceback:
File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/core/handlers/base.py" in get_response
  114.                     response = wrapped_callback(request, *callback_args, **callback_kwargs)
File "/Users/xxxxx/code/ownership/ownership/apps/Assets/crud_views.py" in connect_create_view
  48.             return subview.as_view()(request, model_name=model_name)
File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/views/generic/base.py" in view
  69.             return self.dispatch(request, *args, **kwargs)
File "/Users/xxxxx/.virtualenvs/ownership/lib/python2.7/site-packages/django/views/generic/base.py" in dispatch
  87.         return handler(request, *args, **kwargs)
File "/Users/xxxxx/code/ownership/ownership/apps/Assets/crud_views.py" in post
  280.                 create_new_asset_notification(request, new_item)
File "/Users/xxxxx/code/ownership/ownership/apps/Shared/views.py" in create_new_asset_notification
  123.                 send_email(request, subject, body, owner.to_user().email, )
File "/Users/xxxxx/code/ownership/ownership/apps/Shared/models.py" in to_user
  52.             return User.objects.get(username=str(self.username))

Exception Type: AttributeError at /application/new
Exception Value: 'NoneType' object has no attribute 'objects'
Community
  • 1
  • 1
thumbtackthief
  • 6,093
  • 10
  • 41
  • 87
  • 1
    Difficult to say without seeing your code. Is it possible you accidentally created a variable called `User` that is shadowing the imported class of the same name? – BrenBarn May 19 '14 at 19:42
  • The code base is very large--can definitely include anything you'd like to see. That was my thought too, but I couldn't find anything. What would change the ability to import Item, though? – thumbtackthief May 19 '14 at 19:43
  • Again, hard to say without seeing the code. One thing that could affect it is if there are circular imports, which you said you already suspect. But there's no way for someone to look at the little snippets you pasted and magically say where the problem could be elsewhere in your code; we can only guess. (That doesn't mean you should necessarily paste in a giant amount of code, just that you may need to do some more detailed debugging to narrow it down.) – BrenBarn May 19 '14 at 19:45
  • There's definitely nowhere I'm directly setting User = None. Is it possible I did something globally? – thumbtackthief May 19 '14 at 19:45
  • All the same things Martijn Pieters said in comments on your linked question apply here. – BrenBarn May 19 '14 at 19:46
  • Can you show us a complete traceback? – user2357112 May 19 '14 at 19:46
  • 1
    Still banging your head against the mysterious globals-rebound-to-`None` problem, I see. – Martijn Pieters May 19 '14 at 19:47
  • If it is a circular import, this might help: http://stackoverflow.com/questions/2406007/detecting-circular-imports Dunno if it'll interact properly with the framework, though. – user2357112 May 19 '14 at 19:48
  • @MartijnPieters All day Friday and all day today... I'm about to run off to join the circus. – thumbtackthief May 19 '14 at 19:52
  • from your stack, you clearly have a circular import; `ownership.apps.Assets.models` imports `ownership.apps.Shared.models` imports `ownership.apps.Assets.models` again. fix that first. – Eevee May 19 '14 at 19:53
  • also i would highly recommend not using implicit relative imports like `import permissions` – Eevee May 19 '14 at 19:59
  • I see the circular import, so that's good. No idea how to fix it. Everything does work if I import User within the method that needs to use it. That felt like a bad idea, though. – thumbtackthief May 19 '14 at 20:16

1 Answers1

0

Note this in my stack trace:

 File "/Users/xxxxx/code/ownership/ownership/apps/Assets/models.py", line 12, in <module>
    import permissions   File "/Users/xxxxx/code/ownership/ownership/apps/Assets/permissions.py", line 4, in <module>
    from ownership.apps.Shared.models import Person   File "/Users/xxxxx/code/ownership/ownership/apps/Shared/models.py", line 87, in <module>
    from ownership.apps.Assets.models import Item

Assets/models.py was importing permissions
Permissions was importing Shared.models.Person
Shared/models was importing Assets.models.Item

which was a circular import.

This was corrected by moving from django.contrib.auth.models import User to inside of the Person model. I don't quite understand why--if anyone wants to elaborate and provide a better explanation before I accept my own answer, please do.

thumbtackthief
  • 6,093
  • 10
  • 41
  • 87